紀錄片式 3D 影片(TikTok,德語)
所有內容都以程式碼建構:HyperFrames 加上 Three.js。請先閱讀 hyperframes 技能,其中有合約、check、snapshot 和 render 的說明。
語言:始終使用德語。 這適用於劇本、配音、標題、字幕以及對使用者的回覆。
格式(根據三部參考影片測量)
- 技術規格: 1080×1920,30 fps。
- 長度:標準 60–90 秒(使用者的明確要求;約 150–200 字,10–14 個鏡頭)。只有在明確要求時,長度才能更短。
- 視角: 觀眾就是你。「你走向海灘。」「你坐在莫斯科附近的一個碉堡裡。」「你的鬧鐘響了。」
- 倒數計時結構: 時間是核心骨架。「3 小時後」→「還剩 2.5 小時」→「還剩 30 分鐘」→「第 0 小時」→「+40 分鐘」。或者「第 0/25/100/160 分鐘」或「第 1/3/7/10 天」。轉折點是「第 0 小時」或「第 0 分鐘」。
- 結構:
- 平穩的開場(田園或日常),日期和地點顯示在上方資訊列。
- 徵兆與升級,每個鏡頭都是一次時間跳躍。
- 災難或轉折點。
- 以一個具體數字總結,最好顯示在風格化的地圖上(「≈ 230,000」,警報時數字顯示為紅色)。
- 解釋部分「…平均而言」/「為什麼?」,搭配深色面板與平面示意圖,字幕為「示意圖,非按比例繪製」。
- 結尾:一個教訓或一個向你提出的問題。
- 剪輯: 鏡頭之間使用硬切(每 2–4 秒)。在每個鏡頭內,攝影機作為推軌或推進鏡頭緩慢移動,並在整個鏡頭中使用
smooth()。
設計
3D 世界(Three.js r149,assets/vendor/three.min.js,在場景的 <template> 中載入):
- 風格化、柔和的低多邊形世界,使用光滑材質 (roughness ~0.8),溫暖的陽光和柔和的陰影 (PCFSoft,1024 像素地圖)。
- 天空使用漸層紋理,加上霧氣。色調映射使用 ACES,曝光度約 0.62,否則所有畫面會顯得蒼白。
- 角色 = 關節人偶: 膠囊形的腿、軀幹和手臂,球狀頭部,頭髮帽,單色衣服,沒有臉部。輔助函式
person(seed, {top, pants, scale}),動畫使用idle()/walk(),相位永遠不同步。 - 道具使用方塊、圓柱和球體組成,細節透過
canvasTex()(錶盤、標誌、窗戶)製作。 - 夜晚場景使用自發光窗戶;關燈後,
emissiveIntensity根據距離分級。 - 每個鏡頭是
W.<id> = {scene, camera, update(tLokal, T)},SHOTS定義時間。渲染透過 GSAP 代理 (onUpdate → renderAt) 以及額外的hf-seek完成。 - 模板:
templates/beispiel-keiner-arbeitet/welt.html,包含以下場景:臥室 + 鬧鐘、開放式辦公室、公車站、超市、醫院走廊、垃圾街 + 老鼠、夜晚城市(關燈)、帶蠟燭的廚房、窗戶/陽台。複製輔助函式、場景和渲染器,並重複使用或替換場景。 - 人像畫面裁切很窄(水平約 27°):將攝影機放得比想像中更遠,並將角色置於畫面中央。
- 面板下的定格鏡頭:
{ id, t0, t1, hold: true }以場景的最終狀態進行渲染。
左上角標題區塊(scripts/titel.py,資料在 titel.json),使用 Open Sans 字型,白色,帶柔和陰影:
- 上方資訊列,32 px,600,全大寫字母並增加字距,例如「26. DEZEMBER 2004, ≈ 10:00 UHR」。
- 標題,132 px,700,例如「Noch 30 Min.」、「Minute 0」、「Tag 7」。警報時可顯示為紅色 (
"farbe":"#ff4b3e")。 - 副標題列,32 px,600,全大寫字母,例如「DAS MEER ZIEHT SICH ZURÜCK」。
- 位置:左 72 px,上 228 px。每次剪輯時切換(模糊淡入 0.2 秒)。
字幕(scripts/untertitel.py):
- Open Sans 700 斜體,54 px,垂直居中於 y ≈ 1210。
- 每次顯示一個短語(直到標點符號或最多 5 個詞)。尚未說出的詞語顯示為暗淡 (0.5),並在說話時點亮。
- 關鍵字使用淺藍色
#6cc0ff(--blau "Meer,Welle")。
總結地圖(模板 bilanz.html,路徑來自 europa-paths.json 或 Natural Earth):
- 平面地圖:海洋
#123f73,陸地米色#e9dfc6,目標國家顏色更亮並帶有白色邊框,黃色城市點。 - 白色圓圈從中心脈動,標題區塊中的大數字會向上計數並變為紅色。
解釋部分(模板 erklaerung.html = 鏈條,vorrat.html = 同一條帶中的兩個階段):
- 場景大幅變暗(
rgba(20,26,38,.97)在上方,下方保留些微可見度)。 - 標題區塊「DIE URSACHE / Warum? / SCHEMA, NICHT MASSSTABSGETREU」。
- 一個淺色圖像條帶(y 640–1040),帶有平面插圖(剖面圖、鏈條、腔室…)和全大寫標籤。
- 條帶下方以青色
#5fd0e8顯示狀態文字。 - 使用紅色叉叉或綠色勾勾作為圖示(OpenMoji)。
音效: 配音是時間的基準。精簡使用音效:
- 剪輯時使用 whoosh-short
- 轉折點使用 impact-bass
- 叉叉或警報時使用 error/pop
只有在使用者提供音樂檔案時才加入音樂。
流程(給定主題後,無需提問)
bash scripts/setup.sh(每個容器執行一次),然後bash scripts/projekt.sh <slug>。- 編寫
skript.txt:每個鏡頭一行,使用「你」的形式,簡短的句子。- 長度:60 秒 ≈ 150 字,70 秒 ≈ 165,90 秒 ≈ 210(Piper 約 2.5 字/秒,含停頓)。
- 配音用的數字需拼寫出來,顯示則用
zwölf{12}。 - 事實只有在可靠時才使用;估計值使用「大約」/「約」,思想實驗使用虛擬式或作為情境描述。
python3 scripts/voice.py skript.txt assets/audio --speed 1.08 --gap 0.45- 結果:
voice.wav和words.json,鏡頭根據lines[].start分割。 - 使用者的錄音優先。
- 結果:
titel.json→python3 scripts/titel.py titel.json compositions/titel.htmlpython3 scripts/untertitel.py assets/audio/words.json compositions/untertitel.html --blau "..."- 構建
compositions/welt.html(3D)和compositions/erklaerung.html(示意圖);從模板繼承index.html(圖層:welt 1,erklaerung 2,titel 3,untertitel 4,音訊)。 npx hyperframes check --json(錯誤必須消除;明亮天空上的對比度警告是風格因素)。- 然後
npx hyperframes snapshot --at a,b,c,d,e,f --no-end -o snap,每次調用最多約 6 個時間點。 - 查看圖片並修正。
- 然後
- 背景渲染:
npx hyperframes render -o renders/<slug>.mp4 -q delivery -w 2 --quiet。- WebGL 在 CPU 上運行,需要幾分鐘。
- 之後使用 ffprobe 檢查,查看聯絡表單並將檔案發送給使用者。
配音(使用者要求:友善的女性聲音)
- 偏好:使用者提供的 ElevenLabs 檔案(目前為「Jessica – Playful, Bright, Warm」,eleven_v4)。流程:
- 將劇本作為文字區塊提供給使用者進行錄音(每個鏡頭一行)。
- 使用以下指令產生帶有時間戳的參考檔:
python3 scripts/voice.py skript.txt /tmp/ref --voice ~/.cache/geo-voice/vits-piper-de_DE-kerstin-low/de_DE-kerstin-low.onnx --gap 0.4 - 對齊:
python3 scripts/align.py /tmp/ref assets/audio/<eleven>.mp3 assets/audio(基於 MFCC 的 DTW,行開始時間對齊到實際停頓)。 結果:voice.wav+words.json;使用silencedetect交叉檢查行邊界。 - 所有時間(剪輯點、標題、特效、面板)都從新的詞時間推導出來。
- 無檔案時的替代方案:女性 Piper 聲音(Kerstin/Ramona/Eva,GitHub
k2-fsa/sherpa-onnx的tts-models版本)。這些聽起來很合成;僅作為最後手段,並告知使用者。 - 無法進行語音複製(模型被阻止),也不要模仿第三方或名人聲音。
音樂與音效
使用者總是想要輕柔的背景音樂和效果音。Openverse、Freesound、Pixabay、archive.org 和 HeyGen 被阻止,因此兩者都使用 scripts/klang.py 合成產生。
- 音樂:
python3 scripts/klang.py musik musik-plan.json assets/music/musik.wavmusik-plan.json為每個部分定義:和弦、能量、亮度,以及可選的 BPM 脈衝。此外還有一些鋼琴音符。- 這些部分遵循戲劇性弧線:陰暗 → 緊張(脈衝)→ 低點幾乎安靜 → 溫暖的大調和弦帶來希望。
- 在影片中,
data-volume約 0.22,位於配音下方(音樂檔案約 −18 LUFS)。
- 效果:
python3 scripts/klang.py sfx assets/sfx產生風聲、隆隆聲、收音機、時鐘、腳步聲、車隊、警笛、鐘聲、心跳、嗡嗡聲、爆炸聲。- 此外還有
media-use中附帶的 whoosh/impact/riser。 - 音量 0.15–0.45,持續音效使用
data-fade-in/out。
- 此外還有
- 控制: 使用
showspectrumpic查看頻譜(點擊 = 垂直線)。我無法親自聆聽,因此告知使用者混音是測量而非聽覺調整的結果。 - 對於敏感主題(大屠殺、受害者),減少音樂;僅使用風聲或嗡嗡聲。
敏感的歷史主題
- 禁止使用卐字、SS 符文或其他納粹標誌,以及帶有臉部特徵的加害者肖像(TikTok 會封鎖這些內容,即使在歷史背景下)。旗幟和制服保持抽象。
- 集中營和暴力只能暗示(圍欄、瞭望塔、霧氣),不要展示受害者。語氣應客觀且批判。
- 對於假設情境,在結尾處說明現實情況(「現實」/「為何幾乎不可能」)並展示解放。
持續改進(使用者要求)
每個專案都應在氛圍、效果、動畫和音效上超越前一個。當前狀態位於 templates/beispiel-tschernobyl/:
- 粒子
particles(scene, n, seed, {x,y,z,v,drift,grav,life,color,size,opacity,add,fog}):確定性,並始終使用柔和的圓形紋理SOFT(沒有它會出現方形)。用於火焰、餘燼、煙霧、雨水、灰塵、水柱和落葉。 - 作為敘事的光線: 警報燈閃爍、火焰點光源閃爍、光束是疊加的、地平線上的輝光是漸層平面(不是球體)。
- 攝影機: 撞擊時晃動(
exp(-u*2.2)),每個鏡頭緩慢推軌。 - 外觀圖層
look.html(z-index 在世界之上,在標題/字幕之下):底片顆粒(15 fps,確定性)、暗角、爆炸時白色閃光、靜默時刻淡出黑色、結尾淡出。 - 音效:
klang.py sfx2用於蓋格計數器(3 種密度)、警報、爆炸、火焰、警笛2、公車、雨水和嘎吱聲。在musik-plan.json中有luft(泛音)、sub(低頻)和stille(硬靜音視窗,例如緊接在爆炸後)。此外還有一個 riser,精確地在轉折點前到達(開始 = 撞擊點 − 10.03 秒)。 - 承載結構: 開頭和結尾相互呼應(你睡覺 ↔ 你醒著站在窗前),地圖和示意圖在中間。
陷阱
-
cam()的可視距離只有 400 米。對於所有更遠的物體(地平線、發電廠、拱門),使用camFar(3000+)並將霧氣設定得足夠遠,否則它們會不可見。 -
人像畫面視窗:透過開口精確計劃背景物件(角度 = atan(高度/距離))。
-
品質優先於速度(使用者要求):始終使用 1080×1920,
-q delivery,完整陰影和抗鋸齒。一個 70 秒的渲染在雲端(CPU WebGL)大約需要 40–60 分鐘。請事先告知使用者,不要降低設定。 -
pkill -f <模式>會殺死自己的 shell,如果模式出現在命令中的話。應改用 PID 終止進程。 -
Piper 聲音聽起來很合成(16 kHz)。建議使用自己的錄音或 ElevenLabs 檔案。
-
對於包含未知音素的行,無法進行對齊。
voice.py會根據能量和音節長度分詞;在快照中檢查時間點。 -
場景 ID 必須是唯一的(前綴
er-、ti-、ut-)。 -
容器是臨時的:立即發送影片。技能和專案只有在推送到 Git 儲存庫時才會保留。