[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-1577":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":8,"htmlUrl":8,"language":9,"languages":8,"totalLinesOfCode":8,"stars":10,"forks":11,"watchers":12,"openIssues":13,"contributorsCount":14,"subscribersCount":14,"size":14,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":14,"forks30d":14,"starsTrendScore":18,"compositeScore":19,"rankGlobal":8,"rankLanguage":8,"license":20,"archived":21,"fork":21,"defaultBranch":22,"hasWiki":21,"hasPages":21,"topics":23,"createdAt":8,"pushedAt":8,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":14,"starSnapshotCount":14,"syncStatus":13,"lastSyncTime":27,"discoverSource":28},1577,"Auto-Create-Video","hoquanghai\u002FAuto-Create-Video","hoquanghai",null,"TypeScript",268,156,4,2,0,7,13,37,21,6.59,"MIT License",false,"main",[],"2026-06-12 02:00:29","\u003Ca id=\"top\">\u003C\u002Fa>\n\n\u003Cdiv align=\"center\">\n\n\u003Cimg src=\".\u002Fassets\u002Flogo.svg\" alt=\"Auto News Video\" width=\"120\" \u002F>\n\n# 🎬 Auto News Video\n\n### Turn any Vietnamese tech article into a TikTok-ready video in 60 seconds\n\n**One command. Zero editing. Studio-quality 9:16 motion graphics.**\n\n[![Stars](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fstars\u002Fhoquanghai\u002FAuto-Create-Video?style=for-the-badge&logo=github&color=yellow)](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Fstargazers)\n[![Forks](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Fforks\u002Fhoquanghai\u002FAuto-Create-Video?style=for-the-badge&logo=github&color=blue)](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Fnetwork\u002Fmembers)\n[![License](https:\u002F\u002Fimg.shields.io\u002Fgithub\u002Flicense\u002Fhoquanghai\u002FAuto-Create-Video?style=for-the-badge&color=green)](LICENSE)\n[![Node](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Fnode-22%2B-brightgreen?style=for-the-badge&logo=node.js&logoColor=white)](https:\u002F\u002Fnodejs.org)\n[![TypeScript](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002Ftypescript-5%2B-blue?style=for-the-badge&logo=typescript&logoColor=white)](https:\u002F\u002Fwww.typescriptlang.org\u002F)\n[![Tests](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Factions\u002Fworkflows\u002Ftest.yml\u002Fbadge.svg?style=for-the-badge)](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Factions\u002Fworkflows\u002Ftest.yml)\n[![Typecheck](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Factions\u002Fworkflows\u002Ftypecheck.yml\u002Fbadge.svg?style=for-the-badge)](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Factions\u002Fworkflows\u002Ftypecheck.yml)\n\n[**🇬🇧 English**](README.md) · [**🇻🇳 Tiếng Việt**](README.vi.md) · [**📺 Watch Demo**](https:\u002F\u002Fyoutube.com\u002Fshorts\u002FS24JfKxV4bo) · [**🚀 Quick Start**](#-quick-start) · [**❓ FAQ**](#-faq)\n\n\u003C\u002Fdiv>\n\n---\n\n\u003Cdiv align=\"center\">\n\n## 🎥 Live Demo\n\n### 👉 [**▶️ Watch on YouTube Shorts**](https:\u002F\u002Fyoutube.com\u002Fshorts\u002FS24JfKxV4bo) 👈\n\n[![Watch Demo](https:\u002F\u002Fimg.youtube.com\u002Fvi\u002FS24JfKxV4bo\u002Fmaxresdefault.jpg)](https:\u002F\u002Fyoutube.com\u002Fshorts\u002FS24JfKxV4bo)\n\n[![Watch on YouTube](https:\u002F\u002Fimg.shields.io\u002Fbadge\u002F▶️_Watch_on_YouTube-FF0000?style=for-the-badge&logo=youtube&logoColor=white)](https:\u002F\u002Fyoutube.com\u002Fshorts\u002FS24JfKxV4bo)\n\n*This video was generated **entirely** by this pipeline — Vietnamese TTS + HyperFrames + GSAP animations, no manual editing.*\n\n\u003C\u002Fdiv>\n\n---\n\n## 🤔 Why does this exist?\n\nCreating short-form news videos is **time-consuming and repetitive**:\n\n- ⏰ Manually scripting → 30 min per video\n- 🎨 Picking visuals + animations → 1 hour per video\n- 🎙️ Recording or sourcing voiceover → 30 min\n- ✂️ Editing in CapCut \u002F Premiere → 1 hour\n- 📱 **Total: ~3 hours per 60-second video**\n\n**Auto News Video does it in 5 minutes. Just paste a URL.**\n\n| | Manual workflow | Auto News Video |\n|---|---|---|\n| ⏱️ Time per video | ~3 hours | **~5 minutes** |\n| 🎓 Skill required | Video editor | **None** |\n| 🎯 Consistency | Varies | **Studio-grade every time** |\n| 💰 Cost per video | $50–200 (freelancer) | **~$0.10 (API costs)** |\n| 🇻🇳 Vietnamese voice | Hard to source | **Built-in (LucyLab cloning)** |\n\n---\n\n## 🚀 Quick Start\n\n```bash\n# 1. Clone & install\ngit clone https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video.git\ncd Auto-Create-Video\nnpm install\n\n# 2. Configure TTS API key\ncp .env.example .env.local\n# → edit .env.local, set TTS_PROVIDER + key (LucyLab or ElevenLabs)\n```\n\nThen choose your path:\n\n**Path A — With Claude Code (recommended, 30 seconds setup):**\n\n1. Install Claude Code: `npm install -g @anthropic-ai\u002Fclaude-code`\n2. Inside the project directory, run `claude`, then type:\n   ```\n   \u002Fcreate-news-video https:\u002F\u002Fvnexpress.net\u002Fsome-article\n   ```\n\n**Path B — Without Claude Code (hand-write the script):**\n\n```bash\n# Edit script.json manually based on src\u002Frender\u002Fscript-schema.ts\nnpm run pipeline -- output\u002Fmy-video\u002Fscript.json\n```\n\nEither way, after ~3–5 minutes you'll have `output\u002F\u003Cslug>\u002Fvideo.mp4` — a 1080×1920 MP4 ready for TikTok \u002F Shorts \u002F Reels.\n\n> 💡 **Need details?** Jump to [Full Setup](#-full-setup) · [Configuration](#-configuration) · [Usage](#-usage)\n\n---\n\n## ✨ Features\n\n\u003Ctable>\n\u003Ctr>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🎨 12 Smart Templates\u003C\u002Fh3>\n\u003Csub>hook · comparison · stat-hero · feature-list · callout · outro · quote-card · icon-grid · timeline · big-text · chart-bars · kinetic-quote\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🎤 Multi-TTS\u003C\u002Fh3>\n\u003Csub>LucyLab (Vietnamese cloning + free SRT) or ElevenLabs (30+ languages)\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🤖 Claude Code Skill\u003C\u002Fh3>\n\u003Csub>One slash command:\u003Cbr\u002F>\u003Ccode>\u002Fcreate-news-video &lt;url&gt;\u003C\u002Fcode>\u003Cbr\u002F>(URL \u002F .txt \u002F .md input)\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🎬 HeyGen-Quality Look\u003C\u002Fh3>\n\u003Csub>Studio shell + grain texture + GSAP animations + 6 theme palettes (tech-blue, growth-green, finance-gold, warning-red, creator-purple, news-mono)\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🔊 Auto SFX Mixing\u003C\u002Fh3>\n\u003Csub>3-tier smart picker (override → semantic match → template default) with anti-repetition + anti-overlap guards\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🧪 Production Ready\u003C\u002Fh3>\n\u003Csub>44 unit tests, Zod schema validation, full TypeScript ESM, GitHub Actions CI\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>📱 9:16 Native\u003C\u002Fh3>\n\u003Csub>1080×1920 @ 30fps, ready for TikTok \u002F Shorts \u002F Reels\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>♻️ Idempotent TTS\u003C\u002Fh3>\n\u003Csub>Skips re-synthesis if voice files exist — saves API quota across re-renders\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🖼️ Auto Thumbnail\u003C\u002Fh3>\n\u003Csub>Gemini 2.5 Flash Image generates a 9:16 cover, embedded into MP4 (no re-encode)\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003Ctr>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>🎯 Voice-Text Sync\u003C\u002Fh3>\n\u003Csub>\u003Ccode>voiceChunks\u003C\u002Fcode> per scene → beats fire EXACTLY when voice mentions each element\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>✅ Quality Gates\u003C\u002Fh3>\n\u003Csub>Pre-render \u003Ccode>lint\u003C\u002Fcode> + \u003Ccode>validate\u003C\u002Fcode> (WCAG contrast) + \u003Ccode>inspect\u003C\u002Fcode> (text overflow \u002F off-canvas)\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ch3>📝 CapCut-Friendly\u003C\u002Fh3>\n\u003Csub>Exports \u003Ccode>script.txt\u003C\u002Fcode> + \u003Ccode>voice.mp3\u003C\u002Fcode> + \u003Ccode>sns_post.txt\u003C\u002Fcode> for auto-caption + social caption\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftable>\n\n---\n\n## 🧠 How It Works\n\n```mermaid\nflowchart LR\n    A[📰 URL \u002F .txt \u002F .md] -->|\u002Fcreate-news-video| B[Claude Code]\n    B -->|fetch + analyze| C[Generate script.json]\n    C -->|Zod validate| D{Template Picker}\n    D -->|12 variants| E[Scene Types]\n    E -->|TTS per scene\u003Cbr\u002F>or per chunk| F[LucyLab \u002F ElevenLabs]\n    F -->|voice.mp3\u003Cbr\u002F>+ SFX mix\u003Cbr\u002F>+ beat SFX| G[HyperFrames]\n    G -.->|lint\u003Cbr\u002F>validate\u003Cbr\u002F>inspect| G\n    G -->|Puppeteer + GSAP| H[1800 frames @ 30fps]\n    H -->|FFmpeg encode| I[video.mp4 1080×1920]\n    I -->|attach cover| J[Gemini Thumbnail]\n    J -->|🎬 video.mp4 + thumbnail.png| K[Done]\n\n    style A fill:#0f172a,color:#fff\n    style K fill:#10b981,color:#fff\n    style B fill:#6366f1,color:#fff\n    style F fill:#f59e0b,color:#fff\n    style G fill:#ec4899,color:#fff\n    style J fill:#8b5cf6,color:#fff\n```\n\nThe pipeline is **AI for content** (Claude writes the script) and **deterministic code for production** (Node\u002FTS\u002FFFmpeg renders the pixels) — same input → identical frames every time.\n\n---\n\n## 🛠️ Tech Stack\n\n| Layer | Technology |\n|---|---|\n| **Runtime** | Node.js ≥ 22, TypeScript 6+, ESM |\n| **Render engine** | [HyperFrames](https:\u002F\u002Fhyperframes.heygen.com) ^0.4.34 (Puppeteer + GSAP + FFmpeg) |\n| **Quality gates** | `hyperframes lint` (errors block) → `validate` (WCAG contrast) → `inspect` (text overflow \u002F off-canvas) — all run before render |\n| **TTS providers** | [LucyLab.io](https:\u002F\u002Flucylab.io) (JSON-RPC async, Vietnamese cloning) or [ElevenLabs](https:\u002F\u002Felevenlabs.io) (REST sync, multilingual) |\n| **Image generation** | [Gemini 2.5 Flash Image](https:\u002F\u002Faistudio.google.com) — 9:16 thumbnails, embedded as MP4 cover |\n| **Schema validation** | [Zod](https:\u002F\u002Fzod.dev) ^4 discriminated unions (12 template variants) |\n| **HTTP** | axios ^1.15 + nock (test mocking) |\n| **Concurrency** | [p-limit](https:\u002F\u002Fgithub.com\u002Fsindresorhus\u002Fp-limit) ^7 (TTS rate-limiting per provider) |\n| **Testing** | [Vitest](https:\u002F\u002Fvitest.dev) ^4 — ESM-native, with @vitest\u002Fcoverage-v8 |\n| **Audio processing** | FFmpeg + ffprobe (mix, concat with silence, attach cover image) |\n| **AI orchestration** | [Claude Code](https:\u002F\u002Fdocs.claude.com\u002Fen\u002Fdocs\u002Fclaude-code\u002Foverview) skill (`\u002Fcreate-news-video`) |\n| **Visual blocks** | HyperFrames registry: `grain-overlay`, `shimmer-sweep`, `tiktok-follow` |\n| **Brand spec** | See [`design.md`](design.md) — palette, layout density, motion principles |\n| **Fonts** | Manrope (body) + Anton (display) + Lora (italic serif for quotes) — Google Fonts |\n\n---\n\n## 📋 Prerequisites\n\n| Item | Version | Notes |\n|---|---|---|\n| **Node.js** | ≥ 22 | `node --version` |\n| **FFmpeg + ffprobe** | any modern | must be in PATH (`ffmpeg -version`) |\n| **Chrome \u002F Chromium** | any | auto-downloaded by Puppeteer on first render |\n| **Claude Code CLI** | latest | [install here](https:\u002F\u002Fdocs.claude.com\u002Fen\u002Fdocs\u002Fclaude-code\u002Foverview) |\n| **TTS account** | one of two | LucyLab.io OR ElevenLabs |\n\n---\n\n## 🔧 Full Setup\n\n```bash\n# 1. Clone & enter\ngit clone https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video.git\ncd Auto-Create-Video\n\n# 2. Install\nnpm install\n\n# 3. Configure\ncp .env.example .env.local\n# → open .env.local, set TTS_PROVIDER + API key (see Configuration below)\n\n# 4. Verify\nnode --version       # ≥ 22\nffmpeg -version      # any version OK\nffprobe -version\nnpm test             # 44 tests should pass\n```\n\n### Install FFmpeg\n\n| OS | Command |\n|---|---|\n| **Windows** | `winget install Gyan.FFmpeg` |\n| **macOS** | `brew install ffmpeg` |\n| **Ubuntu\u002FDebian** | `sudo apt install ffmpeg` |\n\n---\n\n## ⚙️ Configuration\n\nOpen `.env.local` and pick **one of two providers**:\n\n### Option 1 — LucyLab.io (recommended for Vietnamese)\n\n```env\nTTS_PROVIDER=lucylab\nVIETNAMESE_API_KEY=sk_live_xxxxxxxxxxxxxxxxxxxx\nVIETNAMESE_VOICEID=22charvoiceiduuidhere\n```\n\n- ✅ Natural Vietnamese voice (cloning), free SRT subtitle file included\n- ⚠️ Only 1 concurrent export per account (pipeline serialises automatically)\n- 🔗 Sign up: https:\u002F\u002Flucylab.io\n\n### Option 2 — ElevenLabs\n\n```env\nTTS_PROVIDER=elevenlabs\nELEVENLABS_API_KEY=sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nELEVENLABS_VOICE_ID=EXAVITQu4vr4xnSDxMaL\nELEVENLABS_MODEL_ID=eleven_multilingual_v2\n```\n\n- ✅ Multilingual (30+ languages), large voice library, high quality\n- ⚠️ Pricier than LucyLab, no SRT included\n- 🔗 Get key: https:\u002F\u002Felevenlabs.io\u002Fapp\u002Fsettings\u002Fapi-keys · Browse voices: https:\u002F\u002Felevenlabs.io\u002Fapp\u002Fvoice-library\n\n### TikTok follow card (optional, all defaults work)\n\n```env\nTIKTOK_DISPLAY_NAME=Quẹp Làm IT\nTIKTOK_HANDLE=@haiquep\nTIKTOK_FOLLOWERS=11.5k followers\nTIKTOK_AVATAR_URL=https:\u002F\u002Fexample.com\u002Fyour-avatar.jpg   # optional\n```\n\nTo customise the avatar, either replace `assets\u002Favatar.png` with your own square ≥256×256 image, **or** set `TIKTOK_AVATAR_URL` so the pipeline downloads it on every render.\n\n### Option 3 — Gemini thumbnail (optional, gracefully skipped if absent)\n\nIf set, the pipeline generates a 9:16 thumbnail per video and embeds it as the MP4 cover image — Windows Explorer \u002F Finder \u002F TikTok \u002F YouTube uploaders show it before any frame plays. Without a key, the step is silently skipped (video still renders).\n\n```env\nGEMINI_API_KEY=YOUR_GEMINI_API_KEY_HERE\nGEMINI_IMAGE_MODEL=gemini-2.5-flash-image    # default; ~7s per call\n```\n\n🔗 Get a free key: https:\u002F\u002Faistudio.google.com\u002Fapikey\n\n### Pipeline tuning (optional)\n\n```env\nTTS_CONCURRENCY=1    # 1 for LucyLab (API limit). Increase for ElevenLabs parallelism.\n```\n\n---\n\n## 🎬 Usage\n\n### Method 1 — Inside Claude Code (recommended)\n\nOpen Claude Code in the project directory and type:\n\n```\n\u002Fcreate-news-video https:\u002F\u002Fvnexpress.net\u002Fiphone-17-200mp\n```\n\nOr with a local file (`.txt` or `.md`):\n\n```\n\u002Fcreate-news-video news\u002Fmy-article.md\n```\n\nAfter ~3–5 minutes:\n\n```\n✓ Video:  output\u002F\u003Cslug>-\u003Ctimestamp>\u002Fvideo.mp4    ← final video\n✓ Audio:  output\u002F\u003Cslug>-\u003Ctimestamp>\u002Fvoice.mp3    ← for CapCut import\n✓ Script: output\u002F\u003Cslug>-\u003Ctimestamp>\u002Fscript.txt   ← for CapCut auto-caption\n```\n\n### Method 2 — Run pipeline directly (advanced)\n\nIf you already have a `script.json` (debugging or hand-written):\n\n```bash\nnpm run pipeline -- output\u002F\u003Cslug>-\u003Ctimestamp>\u002Fscript.json\n```\n\n### Method 3 — Re-render visuals only (saves TTS quota)\n\nWhen voice files already exist in `voice\u002F` and you only want to re-render the visuals:\n\n```bash\nnpm run rerender -- output\u002F\u003Cslug>-\u003Ctimestamp>\n```\n\n---\n\n## 📁 Output Structure\n\n```\noutput\u002F\u003Cslug>-\u003Ctimestamp>\u002F\n├── script.json                # Input JSON (Claude-generated or hand-written)\n├── script.txt                 # Plain text for CapCut auto-caption\n├── sns_post.txt               # Vietnamese caption for TikTok \u002F Reels (skill-generated)\n├── images\u002Fbg.jpg              # og:image (if URL had one)\n├── voice\u002F\n│   ├── scene-hook.mp3         # TTS per scene (idempotent — skipped if exists)\n│   ├── scene-hook.srt         # SRT subtitles (LucyLab only)\n│   ├── scene-body-1.mp3\n│   ├── scene-body-1-chunk-0.mp3   # voiceChunks: per-element TTS files\n│   └── scene-body-1-chunk-1.mp3   # used to compute sync-accurate beat timings\n├── voice-raw.mp3              # Concatenated voices, no SFX (intermediate)\n├── voice.mp3                  # Final audio with SFX + beat SFX mixed in (for CapCut)\n├── tiktok-avatar.png          # Copy of bundled avatar (or downloaded from URL)\n├── logo.svg                   # Copy of bundled logo\n├── index.html                 # HyperFrames composition\n├── styles.css                 # Template CSS (self-contained)\n├── animations.js              # GSAP timeline (self-contained)\n├── hyperframes.json           # HyperFrames manifest\n├── meta.json                  # HyperFrames metadata\n├── thumbnail.png              # Gemini-generated 9:16 cover (if GEMINI_API_KEY set)\n└── video.mp4                  # 🎉 Final output — 1080×1920 @ 30fps + embedded cover\n```\n\n---\n\n## 🎨 Visual System\n\nEvery video has a **persistent shell** throughout (header brand icon + channel + tag, footer TikTok handle, grain texture, gradient background) plus 4–18 scenes auto-picked by Claude. The base palette is **cream editorial (light)** for consistent brand identity; the `theme` field on `script.metadata` switches the accent colour:\n\n| Theme | When to use |\n|---|---|\n| `tech-blue` *(default)* | AI, code, dev tools, software |\n| `growth-green` | Marketing, SaaS, customer growth |\n| `finance-gold` | Money, pricing, ROI, fundraising |\n| `warning-red` | Risk, controversy, failure stories |\n| `creator-purple` | Founder stories, design, art, indie |\n| `news-mono` | Serious news, journalism, reports |\n\n### 12 templates (auto-picked by content)\n\n**v1 — core 6:**\n\n| Template | When it's picked | Example |\n|---|---|---|\n| `hook` | First scene (3–5s) | \"GPT 5.5\" + \"AI mạnh nhất!\" over og:image with Ken Burns + shimmer |\n| `comparison` | Content has \"X vs Y\" \u002F \"exceeds\" \u002F \"compared to\" | 2 cards: \"GPT 5.4 75.1%\" cyan vs \"GPT 5.5 82.7%\" purple (winner) |\n| `stat-hero` | Key number \u002F % | \"1M\" giant gradient + \"Tokens \u002F context window\" |\n| `feature-list` | Listing features | Card with up to 4 bullets, accent glow dots |\n| `callout` | Statement \u002F warning \u002F quote | Glow card with \"Cảnh báo: AI tự chủ cần cân nhắc\" |\n| `outro` | Last scene (3–5s) | \"Theo dõi ngay\" pill + channel name + gradient underline |\n\n**v3 — composition expansion:**\n\n| Template | When it's picked | Example |\n|---|---|---|\n| `quote-card` | Pull quote \u002F contemplative statement | Italic Lora serif, attribution line below |\n| `icon-grid` | 3–6 features \u002F capabilities | Emoji-style icon + label cells, staggered reveal |\n| `timeline` | Multi-stage progression | When\u002Flabel rows, slide-right cascade |\n\n**v3.1 — dramatic impact:**\n\n| Template | When it's picked | Example |\n|---|---|---|\n| `big-text` | Single dramatic word\u002Fphrase | Massive Anton display, optional `hideShell` for full-bleed |\n| `chart-bars` | 2–5 quantitative bars | Heights normalised to 100%, slide-up reveal with ding |\n| `kinetic-quote` | 3–12-word kinetic typography | Words reveal sequentially, accent on highlighted word |\n\n### Per-scene timing & motion\n\n- **Beats** — up to 12 keyed animations per scene (8 effects: `bounce-in`, `scale-pop`, `slide-up\u002F-left\u002F-right`, `fade-in`, `glow-pulse`, `shake`). Defaults derived from template, override via `scene.beats`, or use `voiceChunks` for sync-accurate timing.\n- **`voiceChunks`** — split voice into 2–8 sentences with `target` element + optional `effect` + `sfx`. Pipeline TTS each chunk separately, measures actual durations, fires beats EXACTLY when voice mentions each element. Eliminates the \"visuals leak ahead of voice\" problem.\n- **Transitions** — 8 types (`cut`, `fade`, `slide-up\u002F-down\u002F-left\u002F-right`, `scale-out`, `blur`). Defaults per from→to scene-type pair (e.g. `hook→body`=fade 0.4s, `body→outro`=scale-out 0.5s); override via `scene.transition`.\n\n### Sound Effects (auto-mixed by template)\n\n| Template | Default category (fallback) | When you hear it |\n|---|---|---|\n| `hook` | `transition` → `cinematic` | Dramatic intro |\n| `comparison` | `transition` → `emphasis` | When the 2 cards appear |\n| `stat-hero` | `emphasis` → `success` | When the number reveals |\n| `feature-list` | `transition` → `emphasis` | Each bullet appears |\n| `callout` | `alert` → `drumroll` | Important statement \u002F warning |\n| `outro` | `outro` → `success` | Ending signature |\n| `quote-card` | `cinematic` → `drumroll` | Contemplative pull quote |\n| `icon-grid` | `transition` → `emphasis` | Multi-element reveal |\n| `timeline` | `countdown` → `emphasis` | Stage progression |\n| `big-text` | `cinematic` → `success` | Dramatic impact |\n| `chart-bars` | `emphasis` → `success` | Bar reveal cascade |\n| `kinetic-quote` | `cinematic` → `drumroll` | Typographic reveal |\n\nThe 3-tier SFX picker (in [`src\u002Fassets\u002Fsfx-selector.ts`](src\u002Fassets\u002Fsfx-selector.ts)) chooses in this order:\n\n1. **Explicit `scene.sfx`** override (`\"none\"` disables SFX for that scene)\n2. **Semantic match** on `voiceText` keywords (Vietnamese + English) — e.g. `cảnh báo|warning|risk` → `alert`, `kỷ lục|record|breakthrough` → `success`, `ra mắt|launch|reveal` → `reveal`, `thất bại|fail|crash` → `fail`\n3. **Template default** category (with fallback chain)\n\nWithin a category, files are picked **deterministically** by hashing the scene id (same script → same SFX, but different scenes get different files). Two extra protections run in the mixer:\n\n- **Anti-repetition**: a sliding window of the last 2 scenes prevents the same SFX file twice in a row.\n- **Anti-overlap guard**: per-element beat SFX firing within ±0.4s of a scene's main SFX is suppressed (no \"tick + ding clash\" at scene boundaries). Repeated beat SFX across consecutive scenes get their volume ducked 35%.\n\n---\n\n## 🎥 Showcase\n\n\u003Ctable>\n\u003Ctr>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ca href=\"https:\u002F\u002Fyoutube.com\u002Fshorts\u002FS24JfKxV4bo\">\n\u003Cimg src=\"https:\u002F\u002Fimg.youtube.com\u002Fvi\u002FS24JfKxV4bo\u002F0.jpg\" alt=\"iPhone 17 - 200MP camera\" \u002F>\n\u003C\u002Fa>\n\u003Cbr\u002F>\n\u003Csub>\u003Cb>iPhone 17 — 200MP camera\u003C\u002Fb>\u003Cbr\u002F>Source: VnExpress\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ci>Your video here?\u003C\u002Fi>\u003Cbr\u002F>\u003Cbr\u002F>\n\u003Csub>Open an issue with your output and we'll feature it.\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003Ctd width=\"33%\" align=\"center\">\n\u003Ci>Your video here?\u003C\u002Fi>\u003Cbr\u002F>\u003Cbr\u002F>\n\u003Csub>Open an issue with your output and we'll feature it.\u003C\u002Fsub>\n\u003C\u002Ftd>\n\u003C\u002Ftr>\n\u003C\u002Ftable>\n\n> 🎬 **Made something cool?** Submit your video via [issue](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Fissues\u002Fnew) and we'll feature it here.\n\n---\n\n## ❓ FAQ\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>Can I use this for languages other than Vietnamese?\u003C\u002Fb>\u003C\u002Fsummary>\n\nYes. Switch `TTS_PROVIDER=elevenlabs` in `.env.local` — ElevenLabs supports 30+ languages including English, Chinese, Japanese.\n\nNote: the Claude Code skill currently optimises script generation for Vietnamese. For other languages you may want to adjust the prompts in `.claude\u002Fskills\u002Fcreate-news-video\u002FSKILL.md`.\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>How much does it cost per video?\u003C\u002Fb>\u003C\u002Fsummary>\n\nRoughly **$0.05–0.15 per video**, depending on TTS provider:\n\n- LucyLab: ~$0.02 per video (cheapest, Vietnamese only)\n- ElevenLabs: ~$0.10 per video (multilingual)\n- Claude API (script generation): ~$0.03 per video\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>Can I run this without Claude Code?\u003C\u002Fb>\u003C\u002Fsummary>\n\nYes — use **Method 2** (`npm run pipeline -- script.json`) with a hand-written `script.json`. The Claude Code skill is only used for the \"creative\" step (writing Vietnamese script + picking templates). The pipeline itself is pure Node.js — see [`src\u002Fpipeline.ts`](src\u002Fpipeline.ts).\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>Why HyperFrames instead of Remotion?\u003C\u002Fb>\u003C\u002Fsummary>\n\nHyperFrames is purpose-built for short-form video — 9:16 native, 50+ social media blocks (TikTok cards, kinetic typography, data viz), and AI-agent friendly (Claude can author HTML compositions directly without React boilerplate).\n\nRemotion is a fantastic tool with broader scope — long-form content, complex compositions, full React ecosystem. Different tools for different jobs.\n\nWe still borrow good ideas from Remotion's design:\n\n- Frame-deterministic timeline\n- Declarative scene timing ([`src\u002Frender\u002Ftiming.ts`](src\u002Frender\u002Ftiming.ts))\n- Built-in transition system ([`src\u002Frender\u002Ftransition-profiles.ts`](src\u002Frender\u002Ftransition-profiles.ts))\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>The video output is silent \u002F has garbled audio. What's wrong?\u003C\u002Fb>\u003C\u002Fsummary>\n\nMost likely FFmpeg is missing or not in PATH. Run `ffmpeg -version` to verify.\n\n- Windows: `winget install Gyan.FFmpeg`\n- macOS: `brew install ffmpeg`\n- Ubuntu: `sudo apt install ffmpeg`\n\nThen restart your terminal and re-run.\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>The TTS is mispronouncing numbers. How do I fix it?\u003C\u002Fb>\u003C\u002Fsummary>\n\nVietnamese TTS reads digits literally. Spell them out in `voiceText` (the on-screen text in `templateData` keeps the digit form):\n\n| In `voiceText` (TTS-friendly) | On screen (`templateData`) |\n|---|---|\n| `năm chấm năm` | `5.5` |\n| `tám mươi hai phẩy bảy phần trăm` | `82.7%` |\n| `một triệu token` | `1M tokens` |\n| `hai trăm megapixel` | `200MP` |\n\nThe Claude Code skill handles this automatically when generating scripts. See [`SKILL.md`](.claude\u002Fskills\u002Fcreate-news-video\u002FSKILL.md) for the full phonetic ruleset.\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>Can I customise the visual style (colors, fonts)?\u003C\u002Fb>\u003C\u002Fsummary>\n\nYes — edit [`src\u002Frender\u002Ftemplates\u002Fstyles.css`](src\u002Frender\u002Ftemplates\u002Fstyles.css). The template system uses CSS variables (theme accent + base palette) so changes propagate across all 12 scene types and all 6 themes. Animation timing lives in [`src\u002Frender\u002Ftemplates\u002Fanimations.js`](src\u002Frender\u002Ftemplates\u002Fanimations.js). Brand spec rationale is in [`design.md`](design.md).\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>How do I force re-TTS for a single scene?\u003C\u002Fb>\u003C\u002Fsummary>\n\nThe TTS step is idempotent — it only synthesises scenes whose mp3 doesn't yet exist. To force a single scene, delete its file:\n\n```bash\nrm output\u002F\u003Cslug>\u002Fvoice\u002Fscene-hook.mp3\nnpm run pipeline -- output\u002F\u003Cslug>\u002Fscript.json\n```\n\nTo re-render visuals only (keep all voice files): use `npm run rerender -- output\u002F\u003Cslug>` instead.\n\u003C\u002Fdetails>\n\n\u003Cdetails>\n\u003Csummary>\u003Cb>How long can the video be?\u003C\u002Fb>\u003C\u002Fsummary>\n\nThe pipeline supports **45–180 seconds**. Heuristic in [`SKILL.md`](.claude\u002Fskills\u002Fcreate-news-video\u002FSKILL.md):\n\n| Source words | Script words | Scenes | Duration |\n|---|---|---|---|\n| \u003C 500 | ~110 | 4–5 | ~45–55s |\n| 500–1500 | ~150–200 | 5–8 | ~60–80s |\n| 1500–3000 | ~250–350 | 8–12 | ~100–140s |\n| > 3000 | ~400–500 | 12–18 | ~150–180s |\n\u003C\u002Fdetails>\n\n---\n\n## 🧪 Testing\n\n```bash\nnpm test                 # 44 unit tests (~6s)\nnpm run test:watch       # watch mode\nnpx tsc --noEmit         # type-check without build\n```\n\nTests cover Zod schema validation (12 templates), TTS clients for both LucyLab + ElevenLabs (with `nock` HTTP mocking — no real API calls), audio tools (with fixture mp3 sine waves), beat profiles + chunk-derived beats, timing computation, transition profiles, SFX selector (3-tier + anti-repetition), Gemini thumbnail prompt builder, and HTML composer snapshots. CI runs on every push (see badges at top).\n\n---\n\n## 🐛 Troubleshooting\n\n| Error | Fix |\n|---|---|\n| `Missing VIETNAMESE_API_KEY` \u002F `Missing ELEVENLABS_API_KEY` | Check `.env.local` exists and `TTS_PROVIDER` matches the provider you have keys for |\n| `hyperframes render failed` | Run `npx hyperframes render --help` to verify CLI; ensure Chrome can be downloaded by Puppeteer |\n| `LucyLab polling timeout` | Increase `LUCYLAB_POLL_TIMEOUT_MS` in `.env.local` (default 120000ms) |\n| `ElevenLabs 401 Invalid API key` | Verify the key on the ElevenLabs dashboard, re-paste into `.env.local` |\n| `Total duration outside [45, 180]s` | Pipeline only **warns** — re-trigger the skill or hand-edit `script.json` to lengthen \u002F shorten text. Heuristic in [`SKILL.md`](.claude\u002Fskills\u002Fcreate-news-video\u002FSKILL.md). |\n| `ffprobe: command not found` | Install FFmpeg (see [Configuration](#-configuration)) |\n| `Thumbnail skipped: GEMINI_API_KEY not set` | Optional step. Add a key in `.env.local` (free at https:\u002F\u002Faistudio.google.com\u002Fapikey) or ignore — video still renders fine. |\n| `hyperframes lint failed` | Quality gate caught a composition error. Read the message and fix `index.html` \u002F `animations.js` in the output dir, then re-run `rerender`. |\n\n---\n\n## 🗺️ Roadmap\n\n- [x] ~~Auto thumbnail generation (cover image)~~ — shipped via Gemini 2.5 Flash Image\n- [x] ~~Voice-text sync per element~~ — shipped via `voiceChunks`\n- [x] ~~Quality gates before render~~ — shipped via hyperframes lint\u002Fvalidate\u002Finspect\n- [ ] Burned-in captions (forced alignment with Whisper)\n- [ ] Auto-select background music by mood\n- [ ] Multi-news compilation mode (`digest`)\n- [ ] AI-generated background images for hook scene (Gemini \u002F Flux when og:image unavailable)\n- [ ] Auto-upload to TikTok \u002F YouTube Shorts \u002F Reels via API\n- [ ] Multi-language script generation (English, Chinese, Japanese)\n- [ ] Standalone web UI (no Claude Code required)\n\nHave a feature request? [Open an issue](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Fissues\u002Fnew).\n\n---\n\n## ⭐ Star History\n\n[![Star History Chart](https:\u002F\u002Fapi.star-history.com\u002Fsvg?repos=hoquanghai\u002FAuto-Create-Video&type=Date)](https:\u002F\u002Fstar-history.com\u002F#hoquanghai\u002FAuto-Create-Video&Date)\n\n---\n\n## 🤝 Contributing\n\nPull requests welcome! For major changes, please open an issue first to discuss what you'd like to change.\n\n```bash\n# Fork → clone → branch\ngit checkout -b feature\u002Fmy-improvement\n\n# Make changes, ensure tests pass\nnpm test\nnpx tsc --noEmit\n\n# Commit using Conventional Commits\ngit commit -m \"feat: add Google TTS provider support\"\n\n# Push and open PR\ngit push origin feature\u002Fmy-improvement\n```\n\nCommit prefixes: `feat:` (new feature) · `fix:` (bug) · `docs:` · `refactor:` · `test:` · `chore:`\n\n---\n\n## 📜 License\n\n[MIT](LICENSE) — use freely, fork freely, PRs welcome.\n\n---\n\n## 🙏 Acknowledgements\n\nThis project stands on the shoulders of giants:\n\n- [HyperFrames by HeyGen](https:\u002F\u002Fhyperframes.heygen.com) — the HTML-to-video framework that makes this possible\n- [LucyLab.io](https:\u002F\u002Flucylab.io) — Vietnamese voice cloning API\n- [ElevenLabs](https:\u002F\u002Felevenlabs.io) — multilingual TTS\n- [Anthropic Claude](https:\u002F\u002Fwww.anthropic.com\u002Fclaude) — the LLM that writes scripts via Claude Code skill\n- [Remotion](https:\u002F\u002Fwww.remotion.dev) — inspiration for HTML-based video rendering\n\n---\n\n## 💖 Support this project\n\nIf this project saved you time, please consider:\n\n- ⭐ **[Star this repo](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video)** — it really helps with discoverability\n- 🐦 [Share on Twitter \u002F X](https:\u002F\u002Ftwitter.com\u002Fintent\u002Ftweet?text=Check%20out%20Auto%20News%20Video%20%E2%80%94%20one-command%20Vietnamese%20short-form%20video%20generator&url=https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video)\n- 💬 Tell a friend who creates content\n- 🐛 [Report bugs or request features](https:\u002F\u002Fgithub.com\u002Fhoquanghai\u002FAuto-Create-Video\u002Fissues)\n\n\u003Cdiv align=\"center\">\n\n**[⬆ Back to top](#top)**\n\nMade with ❤️ by [Ho Quang Hai](https:\u002F\u002Fgithub.com\u002Fhoquanghai) in 🇻🇳 Vietnam\n\n\u003C\u002Fdiv>\n","Auto-Create-Video 是一个能够将越南语技术文章转换为适合TikTok发布的视频的工具。其核心功能包括一键生成无需手动编辑的竖屏视频，采用TypeScript编写，并结合了文本转语音、图像选取和动画制作等技术，确保生成的内容达到工作室级别的质量。特别适用于需要快速制作新闻或技术分享短视频的场景，极大减少了传统视频制作过程中所需的时间与技能要求，使得非专业人员也能轻松产出高质量的内容。","2026-06-11 02:44:47","CREATED_QUERY"]