Create Template Video (Chinese)
Turn a piece of Chinese content into a short video in portrait (9:16) or landscape (16:9) format. All design and animation are handled by the HyperFrames templates in templates/, you only need to write the text slots and script.json.
Local Setup Information (DSH Environment, Read First)
-
PROJECT_DIR =
/Users/ming/.agents/skills/create-template-video-zh(skill itself + pipeline + templates;node_modulessymlinked to the Vietnamese version, shared dependencies) -
Directory structure:
SKILL.md,templates/(17 templates +CATALOG.md),src/(CLI/pipeline),package.json,.env(Chinese TTS endpoint). -
Tool mapping: Original uses Claude Code tool names, here they map to DSH:
WebFetch→web_fetch,Read→read,Write→write,Bash→bash. -
Environment dependencies:
ffmpeg/ffprobe✓, Chrome ✓, Node ✓. -
Chinese TTS deployed locally: OmniVoice (MPS) + Mandarin cloned voice
voice-zh.pt, runs on port 8124 (the Vietnamese version fixed on 8123, the two versions do not interfere):bash "$HOME/.agents/skills/create-template-video-zh/scripts/start-tts-zh.sh"The script checks
/health, starts the service in the background, and waits until ready (approx 4 s). Logs are in/tmp/omnivoice-zh.log. After startup, confirm with a Chinese probe:curl -s -X POST http://127.0.0.1:8124/tts -H 'Content-Type: application/json' \ -d '{"text":"大家好,这是中文配音测试。"}' -o /tmp/zh-probe.mp3 && ls -l /tmp/zh-probe.mp3000/cannot connect = not started; if it fails to start, stop and tell the user, do not forge audio. Service directory and deployment notes:/Users/ming/Documents/dsh_workspace/omnivoice(SETUP.md). -
The first render will download HyperFrames via
npx -y [email protected](requires internet, each scene about 15–20s; 8–10 scenes total 3–5 minutes). -
Language: Full video in Chinese. Screen text can mix Chinese and English (
AI,GPT,Appleremain original), butvoiceTextmust be in Chinese, with numbers written in Chinese characters according to the rules below.
Input
1 parameter: a news URL (http:///https://) or a .txt file path.
Workflow (Strict Order)
Step 1–3: Fetch Content + Create Output Directory
- URL →
web_fetchto grab the page, extracttitle,content(main body 800–2000 characters),ogImage(og:image or null),domain. If it fails (paywall/pure JS/4xx) → ask the user to save the content as a.txtfile and run again, then stop. .txt→readthe file;title= first line (≤40 characters),content= remaining text,ogImage=null,domain="local".slug: Prioritize using English or Pinyin keywords (≤40 characters,[a-z0-9-]), e.g.xiaomi-17-price,ai-coding-jobs. If a pure Chinese title cannot be directly converted to ASCII, you write the Pinyin; as a last resort usezh-video(there is also a fallback with the same name in the code).timestamp=YYYYMMDD-HHmm;outputDir=<current workspace>/videos/<slug>-<timestamp>/— place it in the workspace: convenient for delivery and does not pollute the skill directory (DSH sandbox usually only allows writing to the workspace).mkdir -p. The SFX library location is pointed to bySFX_DIRin.envtoassets/sfxwithin the skill, decoupled from the output directory; if the SFX library is empty, that layer is automatically skipped and does not affect the main flow.
Step 4: Read Template Directory
Read PROJECT_DIR/templates/CATALOG.md to confirm templates and slots.
Only use templateId from CATALOG. Currently available:
HOOK (only this one): frame-liquid-bg-hero — aurora light spots + large title + CTA.
BODY (choose based on content, see Step 5):
frame-vignelli— 1 number, dark charcoal background + red.frame-pentagram-stat— 1 number/benchmark, dark background neon (Swiss grid, orange glowing numbers + cyan accents + bar chart).frame-bold-poster— multi-line strong statement + large number.frame-build-minimal— short impactful sentence, dark background + one extra-large bold word (orange glow, character by character).frame-creative-voltage— creative slogan, electric blue split + handwriting style.frame-glitch-title— cyberpunk RGB glitch/fault (noise background), suitable for breaking/tech news.frame-aicoding-list— list of 2–5 items (each with icon + level label), dark gradient background.frame-aicoding-comparison— A vs B comparison (two gradient cards + WIN badge + data).vfx-text-cursor— glitch text + blinking cursor, suitable for one strong opinion/quote (can highlight one word).frame-light-leak-cinema— cinematic light leak + film grain + serif title, suitable for emotional intro/chapter cards.frame-bold-signal— chapter/milestone card, dark background + orange large card + large chapter number + breadcrumb navigation.frame-data-chart-nyt— line chart, paper background NYT style, usesdata[{label,value}]to draw a live curve, end segment can use red dashed line to mark a turning point.frame-decision-tree— decision tree, one question + two branches + two conclusion cards, best for "should I / which one to choose".frame-swiss-grid— Swiss grid, paper background + large title + three numbers, suitable for a "one judgment + three numbers" conclusion page.
OUTRO: frame-logo-outro (default: logo glow + brand + tagline + url);
frame-statement-outro (alternative: paper background red card).
The 17 templates' built-in example values (
data-composition-variables) have all been replaced with Chinese samples, you can see the final effect directly in the preview, or copy them intoscript.jsonand modify. But explicitly passinputsduring rendering: when no parameters are passed, the runtime cannot get the variables, and the text will be empty.All 17 templates have both 9:16 and 16:9 versions (
compositions/portrait.htmlandindex.html), the top-levelaspectinscript.jsondetermines which version is used for the whole video; square (1:1) is not yet provided.
Step 5: Generate script.json
{
"version": "1.0",
"renderer": "hyperframes",
"aspect": "9:16", /* or "16:9"; both ratios have corresponding layouts in each template */
"metadata": {
"title": "...",
"source": { "url": "...", "domain": "...", "image": null },
"channel": "Chinese channel name"
},
"voice": { "provider": "omnivoice", "speed": 1.0 },
"scenes": [
/* 8–12 scenes: 1 hook + 6–10 body + 1 outro */
]
}
providerfixed toomnivoice(local TTS, no voiceId/API key needed).- Each scene:
{ id, type, voiceText, templateId, inputs };inputsmust cover the required slots of that template in CATALOG. scenes[0].type = "hook";scenes[-1].type = "outro"(frame-logo-outro).- 8–12 scenes; total
voiceTextabout 350–450 characters (≈90–120s, Chinese speaking speed about 4.5 characters/second; final duration is based on voiceover, the pipeline aligns to the voiceover). Each body scene 30–45 characters, covering one point only; if a paragraph has two points, split into two scenes. Goal: each scene stays 6–10s.
Content → Template Mapping:
- hook → fixed
frame-liquid-bg-hero(slots: kicker, headline, subheadline, cta, brand).headlinedefaults yellow→purple gradient, can change hue withheadline_from/headline_to(two hex values). - body → you choose the most suitable template based on content, and try to vary, don't use the same one for all bodies:
frame-vignelli: scene has 1 number to emphasize (kicker, number, label, note, brand).frame-pentagram-stat: has 1 baseline/percentage number + bar chart feel (label, headline=number, subtitle, anchor, footer_left, footer_right).frame-build-minimal: short impactful sentence / one keyword (eyebrow, hero=single word, desc, side_left, side_right).frame-bold-poster: multi-line strong statement + large number (kicker, date, figure, headline[], standfirst, footer_left, footer_right). Line 2 ofheadlineautomatically turns red.frame-creative-voltage: creative slogan (meta, display_lines, accent_index, script, caption).frame-glitch-title: breaking/tech/thrilling feel (title, subtitle).frame-aicoding-list: list/comparison of 2–5 items (title, accent, accent_from, accent_to, subtitle, items[]). Each item{icon, title, desc, tag, level}:iconyou choose an emoji (🚫 ⚠️ ✅ ❌ 📈 💡 🔒 🚀 …);level∈danger|warn|good|infodetermines color;taguses a short Chinese label (高危 / 注意 / 利好 / 稳健);accent_from/accent_toyou choose two hex values.frame-aicoding-comparison: exactly compare two things (badge, pre, vs, post, left{}, right{}). Each side{label, from, to, icon?, bullets[], stat?, stat_label?, win?};from/toare gradient two-color hex (cold/warm contrast on each side is better);win: truemarks the winner.vfx-text-cursor: one strong opinion/quote, glitch text + cursor (line1, line2, line3, accent, byline, header_* , footer_*).accentis the word to highlight inline2.frame-light-leak-cinema: emotional intro/chapter card, cinematic light leak + serif title (kicker, title_line1, title_line2, subtitle, header_, footer_).frame-bold-signal: chapter separator/strong statement (section, nav[], card_label, title, footer).frame-data-chart-nyt: use when talking about trends/growth, line chart (kicker, title, highlight, subtitle, data[{label,value}], unit, accent_tail, source_*).frame-decision-tree: talk about "should I / which one" (kicker, question, yes{label,tag,title,desc}, no{...}, footer_*). Only two branches.frame-swiss-grid: conclusion page, one judgment + three numbers (label, title, subtitle, stats[{value,label}], accent_index, footer_*).- Pacing suggestion: when there are many number scenes, alternate between
frame-vignelli(charcoal black+red/yellow) andframe-pentagram-stat(dark neon orange/cyan); for non-number scenes, useframe-build-minimal.
- outro →
frame-logo-outro(brand_name, tagline, primary_url).
Aspect Ratio (aspect, consistent throughout the video):
"9:16"(default, for Douyin/WeChat Video/Shorts) → each template renderscompositions/portrait.html."16:9"(for Bilibili/YouTube/embedded landscape) → rendersindex.html(landscape version of the template)."1:1"(square format for info feed) → requirescompositions/square.html; currently, none of the 17 templates have a square version, selecting 1:1 will fall back to 16:9 with a WARN, the aspect ratio will be wrong — to use square, first addsquare.html.- Both ratios share the same slot names, text can be reused as-is; the difference is only in line width: 16:9 can fit 20–24 characters per line, 9:16 still 10–14 characters.
- Voiceover, duration, and compositing logic are independent of aspect ratio.
Chinese Typography Rules (Screen Text inputs)
- Chinese takes up more space than English/Vietnamese: Keep each line to 10–14 Chinese characters (16:9 landscape can relax to 20–24 characters), if it exceeds, wrap the line or cut text;
headlineat most 3 lines. Better to have two fewer characters than to crowd into two and a half lines. - Template fonts are
Inter Tight+system-ui, Chinese will fall back to PingFang SC (苹方), usually fine; if the rendered result shows boxes/tofu, insert"PingFang SC", "Noto Sans SC",at the beginning of thefont-familyin that template'scompositions/portrait.htmland re-render. - No spaces needed between Chinese words; do not manually add negative
letter-spacingto Chinese, the template's built-in-3pxwill cause characters to stick together. If the title appears too cramped, override withletter-spacing: -1pxon that class. - Emoji is allowed in screen text, but at most 0–1 per field. Do not put emoji in fields with character-by-character animation
(like
frame-build-minimal'shero), otherwise the animation will break. - Numbers on screen retain their display format (
4499 元,82.7%,17), only convert them to Chinese characters invoiceText.
Chinese TTS Rules (voiceText Must Follow Strictly)
OmniVoice reads character by character, so Arabic numerals, decimal points, and currency symbols are often mispronounced or read in English.
Therefore, in voiceText, write all numbers in Chinese characters; inputs (screen text) keep the numbers.
| Format | Wrong Example | Correct Writing |
|---|---|---|
| Decimal | 82.7% | 百分之八十二点七 |
| Version number | iOS 18.2 | iOS 十八点二 |
| Product model | 小米 17 | 小米十七 |
| Pixels | 200MP | 两百万像素 |
| Battery | 5000mAh | 五千毫安时 |
| Quantity | 1M tokens | 一百万 token |
| RMB | ¥4499 | 四千四百九十九元 |
| USD | $5 | 五美元 |
| Multiplier | 2x | 两倍 |
| Percentage | 30% | 百分之三十 |
| Duration | 60s | 六十秒 |
| Ratio | 3:1 | 三比一 |
| Year | 2026 年 | 二零二六年 |
| Trillion | 21 万亿 | 二十一万亿 |
| Ranking | Top 3 | 前三名 |
- For English abbreviations, probe first then decide:
AI,GPT,API,5G,GPUin Chinese TTS are sometimes read letter by letter ("A-I"), sometimes as an English word. Before including in the full video, first use a probe to read two sentences simultaneously for comparison:AI 很强大vs人工智能很强大, choose the writing that sounds more natural, and be consistent throughout the video. - Brand names keep the original (
Apple,OpenAI,小米), Chinese brands write directly in Chinese. - In
voiceText, absolutely forbidden: emoji/icons, URLs, and symbols like& % $ # + = /; use。or?at the end of sentences for natural pauses; use,for commas. - Consistency for "两" vs "二": use "两" for spoken measures (两千、两万、两倍), use "二" for ordinal numbers/years (二零二六年、第二季度).
Step 6: Self-Check
scenes[0]is hook, the last is outro; eachtemplateIdis within CATALOG; eachinputscovers required slots;- Chinese line width ≤14 characters,
headline≤3 lines;voiceTexthas no Arabic numerals/symbols/emoji; emoji only appears ininputs; wording and abbreviation pronunciation are consistent throughout the video; - Total
voiceTextis 350–450 characters. At most 2 rounds of silent correction.
Step 7: Write script.json
Use the write tool to write to <outputDir>/script.json (first mkdir -p the output directory).
Step 8: Run the Pipeline
First start the Chinese TTS (see beginning) and ensure the probe returns audio, then execute in the foreground:
cd "$HOME/.agents/skills/create-template-video-zh" && npm run pipeline -- "<outputDir>/script.json"
The CLI follows renderer: "hyperframes" to run the template pipeline: TTS → per-template render → align to voiceover duration → composite + mix. On failure, report a clear error and give the outputDir path (already rendered
voice/scene-*.mp3, clips/scene-*.mp4 will be reused; just delete them to re-render).
When rerunning after changing Chinese text, first delete the corresponding voice/scene-*.mp3, otherwise the old voiceover will be reused.
Step 9: Deliver
Copy the three deliverables to the session workspace for easy user access:
mkdir -p "<cwd>/videos/<slug>" && cp "<outputDir>"/{video.mp4,voice.mp3,script.txt} "<cwd>/videos/<slug>/"
Then report (using clickable links):
✓ Video: videos/<slug>/video.mp4
✓ Audio: videos/<slug>/voice.mp3 — for Jianying (auto subtitles/lip sync)
✓ Script: videos/<slug>/script.txt — storyboard text, easy for manual editing
Total duration: XX.Xs
Notes
- Each scene renders approx 15–20s (Chromium); 8–10 scenes about 3–5 minutes.
- TTS is idempotent (keeps
voice/scene-*.mp3), clips are also idempotent (keepsclips/scene-*.mp4). - Chinese TTS on M2 Max has an RTF (real-time factor) of about 2.8:1 minute of video takes about 3 minutes of pure TTS.
To speed it up, set the server's
OMNIVOICE_STEPSto16(slightly lower quality, time halved) and restart. - If
assets/sfxis empty, the SFX layer is 0 and does not affect the main flow; to get sound effects, runnpm run sfx:download(requires internet) before generating (default downloads toassets/sfx/within the skill, i.e., the location pointed to bySFX_DIRin.env). Semantic keywords have been added with Chinese (警告/失败/纪录/首次/倒计时/史诗/悬念…). - Differences from the Vietnamese version
create-template-video: TTS port 8124 + Chinese voice, Chinese number pronunciation table, Chinese typography constraints, Chinese SFX keywords,zh-videoslug fallback. The code is an independent copy (onlynode_modulessymlinked to the Vietnamese version); modifying templates/pipeline only affects this directory. If the Vietnamese version is deleted, remember to runnpm cito rebuild dependencies. - Adding a new template: follow the instructions at the end of
templates/CATALOG.md, then add a line in CATALOG.