Spaces:
Running
Running
gemini-stars v2: 星座文化文案改为温和正向表达;新增尾声荣耀时刻(金色桂冠徽章、荣誉铭牌、为你点亮);旁白/音轨/字体/多平台文案同步更新
Browse files- gemini-stars/README.md +8 -6
- gemini-stars/audio.js +14 -6
- gemini-stars/audio/soundtrack.mp3 +2 -2
- gemini-stars/audio/v01.mp3 +0 -0
- gemini-stars/audio/v02.mp3 +0 -0
- gemini-stars/audio/v03.mp3 +0 -0
- gemini-stars/audio/v04.mp3 +0 -0
- gemini-stars/audio/v05.mp3 +0 -0
- gemini-stars/audio/v06.mp3 +0 -0
- gemini-stars/audio/v07.mp3 +0 -0
- gemini-stars/audio/v08.mp3 +0 -0
- gemini-stars/audio/v09.mp3 +0 -0
- gemini-stars/audio/v10.mp3 +0 -0
- gemini-stars/audio/v11.mp3 +0 -0
- gemini-stars/audio/v12.mp3 +0 -0
- gemini-stars/audio/v13.mp3 +0 -0
- gemini-stars/audio/v14.mp3 +0 -0
- gemini-stars/audio/v15.mp3 +0 -0
- gemini-stars/audio/v16.mp3 +0 -0
- gemini-stars/audio/v17.mp3 +0 -0
- gemini-stars/audio/v18.mp3 +0 -0
- gemini-stars/audio/v19.mp3 +0 -0
- gemini-stars/audio/v20.mp3 +0 -0
- gemini-stars/audio/v21.mp3 +0 -0
- gemini-stars/audio/v22.mp3 +0 -0
- gemini-stars/audio/v23.mp3 +0 -0
- gemini-stars/audio/v24.mp3 +0 -0
- gemini-stars/audio/v25.mp3 +0 -0
- gemini-stars/audio/v26.mp3 +0 -0
- gemini-stars/audio/v27.mp3 +0 -0
- gemini-stars/audio/v28.mp3 +0 -0
- gemini-stars/audio/v29.mp3 +0 -0
- gemini-stars/audio/v30.mp3 +0 -0
- gemini-stars/audio/v31.mp3 +0 -0
- gemini-stars/audio/v32.mp3 +0 -0
- gemini-stars/copy.js +23 -22
- gemini-stars/covers/cover-bili-16x9.jpg +2 -2
- gemini-stars/fonts/gemini-sans.woff2 +2 -2
- gemini-stars/fonts/gemini-serif.woff2 +2 -2
- gemini-stars/scenes.js +185 -40
- gemini-stars/timeline.js +38 -20
- gemini-stars/tools/make_voice.py +9 -6
- index.html +1 -1
gemini-stars/README.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
| 23 |
| 封面 | Canvas 渲染:小红书 4:3 & 3:4、抖音 4:3 & 3:4、B 站 4:3 & 16:9、视频号 3:4 & 4:3 |
|
| 24 |
| 文案 | 各平台标题 / 描述 / 话题,自动校验字数与话题数上限,一键复制 |
|
| 25 |
|
| 26 |
-
## 2. 内容大纲(约
|
| 27 |
|
| 28 |
1. **序章 · 冬夜的两颗星**:星空推近,两颗亮星并肩出现,标题浮现。
|
| 29 |
2. **怎样找到它**:冬季夜空,从猎户座腰带向东北方延伸,找到北河二与北河三;双子座连线逐笔描出两个“小人”。
|
|
@@ -32,8 +32,10 @@
|
|
| 32 |
5. **科学 · 北河三**:橙色巨星,约 34 光年,比“哥哥”更亮,还拥有一颗已确认的系外行星。
|
| 33 |
6. **双子座流星雨**:每年 12 月中旬极大,母体是小行星 3200 法厄同,峰值每小时可达一百多颗。
|
| 34 |
7. **星空里的发现**:1781 年赫歇尔在双子座附近发现天王星;1930 年汤博在双子座天区发现冥王星。
|
| 35 |
-
8. **黄道与星座文化**:太阳每年 6 月下旬至 7 月
|
| 36 |
-
9. **尾声**:
|
|
|
|
|
|
|
| 37 |
|
| 38 |
## 3. 技术架构
|
| 39 |
|
|
@@ -46,7 +48,7 @@ gemini-stars/
|
|
| 46 |
├── audio.js # 配乐 / 音效 / 旁白混音(OfflineAudioContext,确定性)
|
| 47 |
├── timeline.js # 由 tools/make_voice.py 生成:每句旁白起止时间与字幕
|
| 48 |
├── copy.js # 小红书 / 抖音 / 哔哩哔哩 / 视频号 标题、描述、话题与封面配置
|
| 49 |
-
├── audio/v01–
|
| 50 |
├── audio/soundtrack.mp3 # 由 audio.js 预渲染的完整混音(秒开;加载失败时浏览器内实时合成)
|
| 51 |
├── fonts/*.woff2 # Noto Sans/Serif SC 子集(OFL),国内网络也能正确显示
|
| 52 |
├── vendor/mp4-muxer.mjs # MIT 许可 MP4 封装库(本地化)
|
|
@@ -73,8 +75,8 @@ gemini-stars/
|
|
| 73 |
- [x] Step 7:自检、修正与最终推送
|
| 74 |
|
| 75 |
### 自检记录
|
| 76 |
-
- 横屏 + 竖屏全片逐帧扫描(24fps ×
|
| 77 |
-
- 无头 Chromium 实测完整导出:24fps / 1280×720 / 3:34,约 2.5 分钟完成,得到含视频与音频的 MP4(该浏览器无 H.264 编码器,自动回退为 VP9 + Opus)。
|
| 78 |
- 手机视口(390×844)自动切换竖屏,播放、字幕、控制条正常。
|
| 79 |
- 音轨:整体响度 -13.6 LUFS,峰值 -1 dB。
|
| 80 |
|
|
|
|
| 23 |
| 封面 | Canvas 渲染:小红书 4:3 & 3:4、抖音 4:3 & 3:4、B 站 4:3 & 16:9、视频号 3:4 & 4:3 |
|
| 24 |
| 文案 | 各平台标题 / 描述 / 话题,自动校验字数与话题数上限,一键复制 |
|
| 25 |
|
| 26 |
+
## 2. 内容大纲(约 4 分 09 秒)
|
| 27 |
|
| 28 |
1. **序章 · 冬夜的两颗星**:星空推近,两颗亮星并肩出现,标题浮现。
|
| 29 |
2. **怎样找到它**:冬季夜空,从猎户座腰带向东北方延伸,找到北河二与北河三;双子座连线逐笔描出两个“小人”。
|
|
|
|
| 32 |
5. **科学 · 北河三**:橙色巨星,约 34 光年,比“哥哥”更亮,还拥有一颗已确认的系外行星。
|
| 33 |
6. **双子座流星雨**:每年 12 月中旬极大,母体是小行星 3200 法厄同,峰值每小时可达一百多颗。
|
| 34 |
7. **星空里的发现**:1781 年赫歇尔在双子座附近发现天王星;1930 年汤博在双子座天区发现冥王星。
|
| 35 |
+
8. **黄道与流传千年的星座文化**:太阳每年 6 月下旬至 7 月下旬穿过双子座天区;在星座文化里,5/21–6/21 出生的人是双子座——心中住着“好奇”与“温柔”两颗星,风象星座、水星守护,灵动、聪慧、妙语连珠。
|
| 36 |
+
9. **尾声 · 致双子座(荣耀时刻)**:北河二与北河三“为你点亮”;金色桂冠徽章「GEMINI · 双子座」在万丈光芒中升起,三块荣誉铭牌——好奇·探索世界的勇气、多面·丰盈闪耀的灵魂、陪伴·永不分离的守候;终章大字「属于你的光 · 致每一位双子座」。
|
| 37 |
+
|
| 38 |
+
> v2 文案调整:星座文化部分改为温和、正向的表达,以“流传千年的文化与祝福”呈现,强调观众的归属感、认可感与荣耀感。
|
| 39 |
|
| 40 |
## 3. 技术架构
|
| 41 |
|
|
|
|
| 48 |
├── audio.js # 配乐 / 音效 / 旁白混音(OfflineAudioContext,确定性)
|
| 49 |
├── timeline.js # 由 tools/make_voice.py 生成:每句旁白起止时间与字幕
|
| 50 |
├── copy.js # 小红书 / 抖音 / 哔哩哔哩 / 视频号 标题、描述、话题与封面配置
|
| 51 |
+
├── audio/v01–v31.mp3 # 31 句中文 AI 旁白
|
| 52 |
├── audio/soundtrack.mp3 # 由 audio.js 预渲染的完整混音(秒开;加载失败时浏览器内实时合成)
|
| 53 |
├── fonts/*.woff2 # Noto Sans/Serif SC 子集(OFL),国内网络也能正确显示
|
| 54 |
├── vendor/mp4-muxer.mjs # MIT 许可 MP4 封装库(本地化)
|
|
|
|
| 75 |
- [x] Step 7:自检、修正与最终推送
|
| 76 |
|
| 77 |
### 自检记录
|
| 78 |
+
- 横屏 + 竖屏全片逐帧扫描(v2:24fps × 249s × 2 ≈ 11,960 帧):0 报错。
|
| 79 |
+
- 无头 Chromium 实测完整导出(v1):24fps / 1280×720 / 3:34,约 2.5 分钟完成,得到含视频与音频的 MP4(该浏览器无 H.264 编码器,自动回退为 VP9 + Opus)。
|
| 80 |
- 手机视口(390×844)自动切换竖屏,播放、字幕、控制条正常。
|
| 81 |
- 音轨:整体响度 -13.6 LUFS,峰值 -1 dB。
|
| 82 |
|
gemini-stars/audio.js
CHANGED
|
@@ -18,8 +18,8 @@ const MOOD = {
|
|
| 18 |
pollux: { prog: 'major', arp: .8, pad: .8, bell: .4 },
|
| 19 |
meteor: { prog: 'dream', arp: 1, pad: .8, bell: .5 },
|
| 20 |
discover: { prog: 'major', arp: .7, pad: .75, bell: .3 },
|
| 21 |
-
zodiac: { prog: 'dream', arp: .
|
| 22 |
-
outro: { prog: 'major', arp: .
|
| 23 |
};
|
| 24 |
const BEAT = .6, CHORD = BEAT * 8;
|
| 25 |
|
|
@@ -141,8 +141,10 @@ export async function buildSoundtrack(onStatus = () => { }, baseUrl = '') {
|
|
| 141 |
});
|
| 142 |
// 尾声终止和弦
|
| 143 |
const outro = S[S.length - 1];
|
| 144 |
-
const fin = outro.lines[
|
| 145 |
-
[62, 66, 69, 74, 78].forEach((m, i) => bell(fin + i * .12, m, .1));
|
|
|
|
|
|
|
| 146 |
|
| 147 |
/* ---------- 音效(与画面时间对齐) ---------- */
|
| 148 |
onStatus('布置音效…');
|
|
@@ -162,8 +164,14 @@ export async function buildSoundtrack(onStatus = () => { }, baseUrl = '') {
|
|
| 162 |
{ const sc = at('meteor'), L = Ls(sc); shimmer(L[1] + .2, .08, 10, 91); whoosh(L[2] + 1.2, .3); ping(L[2] + 2.2, 76, .12); }
|
| 163 |
{ const sc = at('discover'), L = Ls(sc); ping(L[1] + .2, 79, .12); shimmer(L[1] + .8, .07, 8); ping(L[2] + .2, 76, .12);
|
| 164 |
for (let k = 0; k < 8; k++) ping(L[2] + k / 2.2, 96, .03); shimmer(L[2] + 1.4, .07, 8); }
|
| 165 |
-
{ const sc = at('zodiac'), L = Ls(sc); ping(sc.start + .5, 74, .1); shimmer(L[1] - .2, .
|
| 166 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 167 |
|
| 168 |
/* ---------- 旁白 ---------- */
|
| 169 |
const lines = S.flatMap(s => s.lines);
|
|
|
|
| 18 |
pollux: { prog: 'major', arp: .8, pad: .8, bell: .4 },
|
| 19 |
meteor: { prog: 'dream', arp: 1, pad: .8, bell: .5 },
|
| 20 |
discover: { prog: 'major', arp: .7, pad: .75, bell: .3 },
|
| 21 |
+
zodiac: { prog: 'dream', arp: .7, pad: .9, bell: .6 },
|
| 22 |
+
outro: { prog: 'major', arp: .75, pad: 1.1, bell: .8 },
|
| 23 |
};
|
| 24 |
const BEAT = .6, CHORD = BEAT * 8;
|
| 25 |
|
|
|
|
| 141 |
});
|
| 142 |
// 尾声终止和弦
|
| 143 |
const outro = S[S.length - 1];
|
| 144 |
+
const fin = outro.lines[outro.lines.length - 1].start - .3;
|
| 145 |
+
[62, 66, 69, 74, 78, 81, 86].forEach((m, i) => bell(fin + i * .12, m, .1));
|
| 146 |
+
const crown = outro.lines[2].start - 1;
|
| 147 |
+
[50, 57, 62, 66, 69, 74].forEach((m, i) => bell(crown + i * .09, m + 12, .09));
|
| 148 |
|
| 149 |
/* ---------- 音效(与画面时间对齐) ---------- */
|
| 150 |
onStatus('布置音效…');
|
|
|
|
| 164 |
{ const sc = at('meteor'), L = Ls(sc); shimmer(L[1] + .2, .08, 10, 91); whoosh(L[2] + 1.2, .3); ping(L[2] + 2.2, 76, .12); }
|
| 165 |
{ const sc = at('discover'), L = Ls(sc); ping(L[1] + .2, 79, .12); shimmer(L[1] + .8, .07, 8); ping(L[2] + .2, 76, .12);
|
| 166 |
for (let k = 0; k < 8; k++) ping(L[2] + k / 2.2, 96, .03); shimmer(L[2] + 1.4, .07, 8); }
|
| 167 |
+
{ const sc = at('zodiac'), L = Ls(sc); ping(sc.start + .5, 74, .1); shimmer(L[1] - .2, .12, 14, 86); boom(L[1] - .3, .3);
|
| 168 |
+
ping(L[2] + .4, 88, .1); ping(L[2] + 4, 91, .1); ping(L[2] + 7.5, 86, .1);
|
| 169 |
+
for (let k = 0; k < 3; k++) ping(L[3] + 2.2 + k * .8, 86 + k * 2, .09); }
|
| 170 |
+
{ const sc = at('outro'), L = Ls(sc); shimmer(sc.start + .5, .08, 10); for (let k = 0; k < 3; k++) ping(sc.start + 1 + k * .9, 84 + k * 3, .08);
|
| 171 |
+
shimmer(L[1] + .5, .08, 10, 88); ping(L[1] + 3, 86, .1);
|
| 172 |
+
boom(L[2] - 1, .55); whoosh(L[2] - 1.6, .4); shimmer(L[2] - .8, .12, 18, 86);
|
| 173 |
+
for (let k = 0; k < 3; k++) { ping(L[2] + 1.5 + k * 2.6, 81 + k * 4, .12); shimmer(L[2] + 1.6 + k * 2.6, .05, 6, 93); }
|
| 174 |
+
shimmer(L[4] - .3, .12, 20, 86); boom(L[4] - .3, .4); }
|
| 175 |
|
| 176 |
/* ---------- 旁白 ---------- */
|
| 177 |
const lines = S.flatMap(s => s.lines);
|
gemini-stars/audio/soundtrack.mp3
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:e1f107a5f7ccfab06fe967466b91caa306b46c0df5af01a50f49becee1f08da3
|
| 3 |
+
size 5983532
|
gemini-stars/audio/v01.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v01.mp3 and b/gemini-stars/audio/v01.mp3 differ
|
|
|
gemini-stars/audio/v02.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v02.mp3 and b/gemini-stars/audio/v02.mp3 differ
|
|
|
gemini-stars/audio/v03.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v03.mp3 and b/gemini-stars/audio/v03.mp3 differ
|
|
|
gemini-stars/audio/v04.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v04.mp3 and b/gemini-stars/audio/v04.mp3 differ
|
|
|
gemini-stars/audio/v05.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v05.mp3 and b/gemini-stars/audio/v05.mp3 differ
|
|
|
gemini-stars/audio/v06.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v06.mp3 and b/gemini-stars/audio/v06.mp3 differ
|
|
|
gemini-stars/audio/v07.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v07.mp3 and b/gemini-stars/audio/v07.mp3 differ
|
|
|
gemini-stars/audio/v08.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v08.mp3 and b/gemini-stars/audio/v08.mp3 differ
|
|
|
gemini-stars/audio/v09.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v09.mp3 and b/gemini-stars/audio/v09.mp3 differ
|
|
|
gemini-stars/audio/v10.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v10.mp3 and b/gemini-stars/audio/v10.mp3 differ
|
|
|
gemini-stars/audio/v11.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v11.mp3 and b/gemini-stars/audio/v11.mp3 differ
|
|
|
gemini-stars/audio/v12.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v12.mp3 and b/gemini-stars/audio/v12.mp3 differ
|
|
|
gemini-stars/audio/v13.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v13.mp3 and b/gemini-stars/audio/v13.mp3 differ
|
|
|
gemini-stars/audio/v14.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v14.mp3 and b/gemini-stars/audio/v14.mp3 differ
|
|
|
gemini-stars/audio/v15.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v15.mp3 and b/gemini-stars/audio/v15.mp3 differ
|
|
|
gemini-stars/audio/v16.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v16.mp3 and b/gemini-stars/audio/v16.mp3 differ
|
|
|
gemini-stars/audio/v17.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v17.mp3 and b/gemini-stars/audio/v17.mp3 differ
|
|
|
gemini-stars/audio/v18.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v18.mp3 and b/gemini-stars/audio/v18.mp3 differ
|
|
|
gemini-stars/audio/v19.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v19.mp3 and b/gemini-stars/audio/v19.mp3 differ
|
|
|
gemini-stars/audio/v20.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v20.mp3 and b/gemini-stars/audio/v20.mp3 differ
|
|
|
gemini-stars/audio/v21.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v21.mp3 and b/gemini-stars/audio/v21.mp3 differ
|
|
|
gemini-stars/audio/v22.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v22.mp3 and b/gemini-stars/audio/v22.mp3 differ
|
|
|
gemini-stars/audio/v23.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v23.mp3 and b/gemini-stars/audio/v23.mp3 differ
|
|
|
gemini-stars/audio/v24.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v24.mp3 and b/gemini-stars/audio/v24.mp3 differ
|
|
|
gemini-stars/audio/v25.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v25.mp3 and b/gemini-stars/audio/v25.mp3 differ
|
|
|
gemini-stars/audio/v26.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v26.mp3 and b/gemini-stars/audio/v26.mp3 differ
|
|
|
gemini-stars/audio/v27.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v27.mp3 and b/gemini-stars/audio/v27.mp3 differ
|
|
|
gemini-stars/audio/v28.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v28.mp3 and b/gemini-stars/audio/v28.mp3 differ
|
|
|
gemini-stars/audio/v29.mp3
CHANGED
|
Binary files a/gemini-stars/audio/v29.mp3 and b/gemini-stars/audio/v29.mp3 differ
|
|
|
gemini-stars/audio/v30.mp3
ADDED
|
Binary file (59.3 kB). View file
|
|
|
gemini-stars/audio/v31.mp3
ADDED
|
Binary file (30.2 kB). View file
|
|
|
gemini-stars/audio/v32.mp3
ADDED
|
Binary file (22.3 kB). View file
|
|
|
gemini-stars/copy.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
| 2 |
export const PLATFORMS = [
|
| 3 |
{
|
| 4 |
id: 'xhs', name: '小红书', titleMax: 20, tagMax: 10, tagStyle: 'hash',
|
| 5 |
-
title: '双子座:
|
| 6 |
desc: `冬夜抬头,东方那两颗肩并肩的亮星,就是双子座的“头”🌟
|
| 7 |
🔭 怎么找:猎户座腰带 → 往东北方看
|
| 8 |
🏛 神话:凡人哥哥卡斯托尔 × 不朽弟弟波吕克斯,弟弟把永生分了一半给哥哥
|
|
@@ -10,27 +10,28 @@ export const PLATFORMS = [
|
|
| 10 |
🧡 北河三:橙色巨星,比“二号”哥哥还亮,身边还有一颗行星
|
| 11 |
☄️ 双子座流星雨:12 月中旬,母体竟是小行星法厄同
|
| 12 |
🪐 天王星、冥王星的发现都和它有关
|
| 13 |
-
|
| 14 |
-
|
|
|
|
| 15 |
covers: [
|
| 16 |
-
{ ratio: '4:3', w: 1440, h: 1080, label: '横封面 4:3', hook: '
|
| 17 |
-
{ ratio: '3:4', w: 1080, h: 1440, label: '竖封面 3:4', hook: '
|
| 18 |
],
|
| 19 |
},
|
| 20 |
{
|
| 21 |
id: 'douyin', name: '抖音', titleMax: 30, tagMax: 5, tagStyle: 'hash',
|
| 22 |
-
title: '一颗星藏着6颗恒星
|
| 23 |
-
desc: '肉眼看是一颗星,望远镜里却是 6 颗恒星!
|
| 24 |
-
tags: ['双子座', '
|
| 25 |
covers: [
|
| 26 |
-
{ ratio: '4:3', w: 1440, h: 1080, label: '横封面 4:3', hook: '
|
| 27 |
-
{ ratio: '3:4', w: 1080, h: 1440, label: '竖封面 3:4', hook: '
|
| 28 |
],
|
| 29 |
},
|
| 30 |
{
|
| 31 |
id: 'bili', name: '哔哩哔哩', titleMax: 80, tagMax: 10, tagStyle: 'plain',
|
| 32 |
-
title: '【星空动画】双子座
|
| 33 |
-
desc: `全程手工编程的星空动画,
|
| 34 |
00:00 序章 · 冬夜的两颗星
|
| 35 |
00:15 怎样找到它(猎户座腰带 → 东北方)
|
| 36 |
00:40 神话 · 卡斯托尔与波吕克斯
|
|
@@ -38,23 +39,23 @@ export const PLATFORMS = [
|
|
| 38 |
01:45 北河三 · 橙色巨星与它的行星(约 34 光年)
|
| 39 |
02:06 双子座流星雨 · 母体为小行星 3200 法厄同
|
| 40 |
02:28 星空里的发现 · 1781 天王星 / 1930 冥王星
|
| 41 |
-
02:46 黄道与星座文化
|
| 42 |
-
03:
|
| 43 |
-
数据为常见
|
| 44 |
tags: ['双子座', '天文', '科普', '星座', '希腊神话', '流星雨', '星空', '宇宙', '动画', '知识分享'],
|
| 45 |
covers: [
|
| 46 |
-
{ ratio: '4:3', w: 1440, h: 1080, label: '视频封面 4:3', hook: '双子座
|
| 47 |
-
{ ratio: '16:9', w: 1920, h: 1080, label: '个人空间封面 16:9', hook: '双子座
|
| 48 |
],
|
| 49 |
},
|
| 50 |
{
|
| 51 |
id: 'wx', name: '微信视频号', titleMax: 16, tagMax: Infinity, tagStyle: 'hash',
|
| 52 |
-
title: '双子座:
|
| 53 |
-
desc: '冬夜东方的两颗亮星,是一对兄弟的约定。
|
| 54 |
-
tags: ['双子座', '星座', '
|
| 55 |
covers: [
|
| 56 |
-
{ ratio: '3:4', w: 1080, h: 1440, label: '个人主页卡片 3:4', hook: '
|
| 57 |
-
{ ratio: '4:3', w: 1440, h: 1080, label: '分享卡片 4:3', hook: '
|
| 58 |
],
|
| 59 |
},
|
| 60 |
];
|
|
|
|
| 2 |
export const PLATFORMS = [
|
| 3 |
{
|
| 4 |
id: 'xhs', name: '小红书', titleMax: 20, tagMax: 10, tagStyle: 'hash',
|
| 5 |
+
title: '致双子座:你是两束并肩的光✨',
|
| 6 |
desc: `冬夜抬头,东方那两颗肩并肩的亮星,就是双子座的“头”🌟
|
| 7 |
🔭 怎么找:猎户座腰带 → 往东北方看
|
| 8 |
🏛 神话:凡人哥哥卡斯托尔 × 不朽弟弟波吕克斯,弟弟把永生分了一半给哥哥
|
|
|
|
| 10 |
🧡 北河三:橙色巨星,比“二号”哥哥还亮,身边还有一颗行星
|
| 11 |
☄️ 双子座流星雨:12 月中旬,母体竟是小行星法厄同
|
| 12 |
🪐 天王星、冥王星的发现都和它有关
|
| 13 |
+
🌟 人们说,双子座心里住着两颗星:一颗是好奇,一颗是温柔
|
| 14 |
+
4 分钟星空动画,献给每一位双子座——那是属于你的星座,也是属于你的光✨`,
|
| 15 |
+
tags: ['双子座', '星座', '双子座女生', '双子座男生', '星空', '希腊神话', '双子座流星雨', '天文科普', '星座文化', '治愈系'],
|
| 16 |
covers: [
|
| 17 |
+
{ ratio: '4:3', w: 1440, h: 1080, label: '横封面 4:3', hook: '致双子座:你是两束并肩的光', tags: ['好奇', '温柔', '闪耀'] },
|
| 18 |
+
{ ratio: '3:4', w: 1080, h: 1440, label: '竖封面 3:4', hook: '你是两束并肩的光', tags: ['好奇', '温柔', '闪耀'] },
|
| 19 |
],
|
| 20 |
},
|
| 21 |
{
|
| 22 |
id: 'douyin', name: '抖音', titleMax: 30, tagMax: 5, tagStyle: 'hash',
|
| 23 |
+
title: '双子座看过来!一颗星藏着6颗恒星,这是属于你的星空',
|
| 24 |
+
desc: '肉眼看是一颗星,望远镜里却是 6 颗恒星!兄弟神话、橙色巨星、冬夜流星雨……双子座的星空,比你想象的更闪耀。你的好奇是勇气,你的多面是丰盈——致每一位双子座✨',
|
| 25 |
+
tags: ['双子座', '星座', '星空', '双子座流星雨', '天文科普'],
|
| 26 |
covers: [
|
| 27 |
+
{ ratio: '4:3', w: 1440, h: 1080, label: '横封面 4:3', hook: '这是属于你的星空', tags: ['神话', '六星家族', '流星雨'] },
|
| 28 |
+
{ ratio: '3:4', w: 1080, h: 1440, label: '竖封面 3:4', hook: '这是属于你的星空', tags: ['神话', '六星家族', '流星雨'] },
|
| 29 |
],
|
| 30 |
},
|
| 31 |
{
|
| 32 |
id: 'bili', name: '哔哩哔哩', titleMax: 80, tagMax: 10, tagStyle: 'plain',
|
| 33 |
+
title: '【星空动画】致每一位双子座:一颗星竟藏着6颗恒星,流星雨母体是小行星,还见证了天王星与冥王星的发现',
|
| 34 |
+
desc: `全程手工编程的星空动画,献给每一位双子座:
|
| 35 |
00:00 序章 · 冬夜的两颗星
|
| 36 |
00:15 怎样找到它(猎户座腰带 → 东北方)
|
| 37 |
00:40 神话 · 卡斯托尔与波吕克斯
|
|
|
|
| 39 |
01:45 北河三 · 橙色巨星与它的行星(约 34 光年)
|
| 40 |
02:06 双子座流星雨 · 母体为小行星 3200 法厄同
|
| 41 |
02:28 星空里的发现 · 1781 天王星 / 1930 冥王星
|
| 42 |
+
02:46 黄道与流传千年的星座文化 · 心中的两颗星
|
| 43 |
+
03:26 尾声 · 致双子座:属于你的光
|
| 44 |
+
天文数据为常见资料的近似值,欢迎在评论区和大家分享你身边的双子座~`,
|
| 45 |
tags: ['双子座', '天文', '科普', '星座', '希腊神话', '流星雨', '星空', '宇宙', '动画', '知识分享'],
|
| 46 |
covers: [
|
| 47 |
+
{ ratio: '4:3', w: 1440, h: 1080, label: '视频封面 4:3', hook: '致每一位双子座', tags: ['神话', '六星家族', '流星雨'], badge: '星空动画' },
|
| 48 |
+
{ ratio: '16:9', w: 1920, h: 1080, label: '个人空间封面 16:9', hook: '致每一位双子座', tags: ['神话', '六星家族', '流星雨'], badge: '星空动画' },
|
| 49 |
],
|
| 50 |
},
|
| 51 |
{
|
| 52 |
id: 'wx', name: '微信视频号', titleMax: 16, tagMax: Infinity, tagStyle: 'hash',
|
| 53 |
+
title: '致双子座:属于你的光',
|
| 54 |
+
desc: '冬夜东方的两颗亮星,是一对兄弟永不分离的约定。4 分钟星空动画,带你读懂双子座的神话、星空与千年文化——转给你身边的双子座吧✨',
|
| 55 |
+
tags: ['双子座', '星座', '星座文化', '星空', '希腊神话', '流星雨', '冬季星空', '天文科普', '治愈', '宇宙'],
|
| 56 |
covers: [
|
| 57 |
+
{ ratio: '3:4', w: 1080, h: 1440, label: '个人主页卡片 3:4', hook: '属于你的光', tags: ['好奇', '温柔', '闪耀'] },
|
| 58 |
+
{ ratio: '4:3', w: 1440, h: 1080, label: '分享卡片 4:3', hook: '属于你的光', tags: ['好奇', '温柔', '闪耀'] },
|
| 59 |
],
|
| 60 |
},
|
| 61 |
];
|
gemini-stars/covers/cover-bili-16x9.jpg
CHANGED
|
Git LFS Details
|
|
Git LFS Details
|
gemini-stars/fonts/gemini-sans.woff2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a38144aa87625221063ebd8a4e96b7e39d61d9fc4fa96f561cf42ca731ecdeaf
|
| 3 |
+
size 228268
|
gemini-stars/fonts/gemini-serif.woff2
CHANGED
|
@@ -1,3 +1,3 @@
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
-
oid sha256:
|
| 3 |
-
size
|
|
|
|
| 1 |
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:7c98a450689b239651c10b554f560ef04af74e925c9bf9a1b31c9f695d082709
|
| 3 |
+
size 299188
|
gemini-stars/scenes.js
CHANGED
|
@@ -794,69 +794,214 @@ SC.zodiac = (ctx, lt, D, W, H, L, t) => {
|
|
| 794 |
chip(ctx, '太阳在双子座天区:约 6/21 – 7/20', cx, port ? H * .72 : H * .1, 28 * u, ring * sstep(2, 3, lt));
|
| 795 |
}
|
| 796 |
if (culture > 0) {
|
| 797 |
-
//
|
| 798 |
-
const gx = port ? W / 2 : W * .
|
| 799 |
-
|
| 800 |
-
|
| 801 |
-
|
| 802 |
-
ctx.
|
| 803 |
-
|
| 804 |
-
|
| 805 |
-
|
| 806 |
-
|
| 807 |
-
|
| 808 |
-
|
| 809 |
-
|
| 810 |
-
|
| 811 |
-
|
| 812 |
-
|
| 813 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 814 |
words.forEach(([w, col], i) => {
|
| 815 |
-
const a = sstep(L[
|
| 816 |
-
const x = tx + (i - 1) * (port ?
|
| 817 |
-
ctx.save(); ctx.globalAlpha = a; ctx.translate(x, y);
|
| 818 |
-
|
| 819 |
-
|
|
|
|
| 820 |
});
|
| 821 |
-
|
|
|
|
| 822 |
}
|
| 823 |
};
|
| 824 |
|
| 825 |
-
/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 826 |
SC.outro = (ctx, lt, D, W, H, L, t) => {
|
| 827 |
const { u, port } = layout(W, H);
|
| 828 |
-
const
|
| 829 |
-
const
|
|
|
|
| 830 |
drawLines(ctx, view, GEM_LINES, 1, 'rgba(255,190,110,.22)', 24 * u, a * .6);
|
| 831 |
drawLines(ctx, view, GEM_LINES, sstep(0, 3, lt), 'rgba(255,230,180,.95)', 2.6 * u, a);
|
| 832 |
-
drawStarSet(ctx, view, GEM_KEYS, t, u, a, { castor: 1.4, pollux: 1.5 });
|
| 833 |
-
// 回顾
|
| 834 |
-
const icons = [['兄弟', '#ffe1a0'], ['流星雨', '#cfe0ff'], ['六星家族', '#ffd0a0']];
|
| 835 |
icons.forEach(([s, col], i) => chip(ctx, s, W / 2 + (i - 1) * (port ? 250 : 260) * u, H * (port ? .62 : .74), 28 * u, sstep(.8 + i * .9, 1.8 + i * .9, lt) * (1 - sstep(L[1] - .5, L[1] + .5, lt)), col));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 836 |
// 流星
|
| 837 |
const r = rng(3);
|
| 838 |
-
for (let i = 0; i <
|
| 839 |
-
const t0 = 2 + i * 3.
|
| 840 |
-
const x = W * (.
|
| 841 |
const x1 = x + k * 300 * u, y1 = y + k * 150 * u;
|
| 842 |
-
const g = ctx.createLinearGradient(x1 - len, y1 - len / 2, x1, y1); g.addColorStop(0, 'rgba(255,255,255,0)'); g.addColorStop(1, `rgba(255,
|
| 843 |
ctx.strokeStyle = g; ctx.lineWidth = 2.5 * u; ctx.beginPath(); ctx.moveTo(x1 - len * .9, y1 - len * .45); ctx.lineTo(x1, y1); ctx.stroke();
|
| 844 |
}
|
| 845 |
-
// 结尾
|
| 846 |
-
const e = sstep(L[
|
| 847 |
if (e > 0) {
|
| 848 |
-
const ty = H * (port ? .
|
| 849 |
ctx.save(); ctx.globalAlpha = e; ctx.font = `900 ${size}px ${SERIF}`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
|
| 850 |
-
ctx.shadowColor = 'rgba(255,
|
| 851 |
-
ctx.fillText('
|
| 852 |
-
text(ctx, '双子
|
| 853 |
}
|
| 854 |
// 最后淡出
|
| 855 |
const out = sstep(D - 2.2, D, lt);
|
| 856 |
if (out > 0) { ctx.fillStyle = `rgba(0,0,0,${out})`; ctx.fillRect(0, 0, W, H); }
|
| 857 |
};
|
| 858 |
|
| 859 |
-
const CHAPTERS = { intro: '序章', find: '怎样找到它', myth: '神话 · 孪生兄弟', castor: '北河二 · 六星家族', pollux: '北河三 · 橙色巨星', meteor: '双子座流星雨', discover: '星空里的发现', zodiac: '黄道与星座文化', outro: '尾声' };
|
| 860 |
const CAMS = { intro: [0, 0], find: [1, .4], myth: [2, .8], castor: [3, 1.1], pollux: [4, 1.5], meteor: [5, 2.1], discover: [6, 2.5], zodiac: [7, 2.9], outro: [8, 3.3] };
|
| 861 |
|
| 862 |
/* ---------------- 主渲染 ---------------- */
|
|
|
|
| 794 |
chip(ctx, '太阳在双子座天区:约 6/21 – 7/20', cx, port ? H * .72 : H * .1, 28 * u, ring * sstep(2, 3, lt));
|
| 795 |
}
|
| 796 |
if (culture > 0) {
|
| 797 |
+
// 背景金色光芒
|
| 798 |
+
const gx = port ? W / 2 : W * .3, gy = port ? H * .27 : H * .45, s = (port ? 280 : 320) * u;
|
| 799 |
+
godRays(ctx, gx, gy, s * 2.2, lt * .05, culture * .55, 18);
|
| 800 |
+
drawStar(ctx, gx, gy, s * .35, '#ffcf7a', culture * .35);
|
| 801 |
+
drawGlyph(ctx, gx, gy, s, culture, u);
|
| 802 |
+
text(ctx, '5.21 – 6.21', gx, gy + s * .5, 40 * u, '#ffe6b0', 'center', culture, SERIF, 800, 'rgba(255,190,90,.6)');
|
| 803 |
+
// 两颗心星:好奇 / 温柔(环绕符号)
|
| 804 |
+
const two = sstep(L[2] + .3, L[2] + 1.5, lt);
|
| 805 |
+
if (two > 0) {
|
| 806 |
+
const R = s * .78;
|
| 807 |
+
[['好奇', '#9fe0ff', 0, L[2] + 4], ['温柔', '#ffc7a0', Math.PI, L[2] + 7.5]].forEach(([w, col, ph, tt]) => {
|
| 808 |
+
const ang = ph + lt * .35 - .4, x = gx + Math.cos(ang) * R, y = gy + Math.sin(ang) * R * .42;
|
| 809 |
+
const hl = 1 + .5 * sstep(tt - .5, tt + .5, lt) * (1 - sstep(tt + 2.5, tt + 3.5, lt));
|
| 810 |
+
drawStar(ctx, x, y, 14 * u * hl, col, two, .9);
|
| 811 |
+
text(ctx, w, x, y - 44 * u, 34 * u * Math.min(hl, 1.2), col, 'center', two, SERIF, 900, col);
|
| 812 |
+
});
|
| 813 |
+
ctx.save(); ctx.globalAlpha = two * .35; ctx.strokeStyle = '#ffe1a0'; ctx.lineWidth = 1.5 * u; ctx.setLineDash([3 * u, 8 * u]);
|
| 814 |
+
ctx.beginPath(); ctx.ellipse(gx, gy, R, R * .42, 0, 0, TAU); ctx.stroke(); ctx.restore();
|
| 815 |
+
}
|
| 816 |
+
// 右侧文字
|
| 817 |
+
const tx = port ? W / 2 : W * .68, ty = port ? H * .55 : H * .28;
|
| 818 |
+
text(ctx, '流传千年的星座文化', tx, ty, 40 * u, '#fff4dc', 'center', culture, SERIF, 800, 'rgba(255,200,120,.5)');
|
| 819 |
+
ctx.save(); ctx.globalAlpha = culture; ctx.strokeStyle = goldGrad(ctx, tx - 200 * u, 0, tx + 200 * u, 0); ctx.lineWidth = 1.5 * u;
|
| 820 |
+
ctx.beginPath(); ctx.moveTo(tx - 200 * u * culture, ty + 34 * u); ctx.lineTo(tx + 200 * u * culture, ty + 34 * u); ctx.stroke(); ctx.restore();
|
| 821 |
+
const lines2 = [['心中两颗星', '好奇 · 温柔', L[2] + .6], ['风象星座', '水星守护', L[3] + .2]];
|
| 822 |
+
lines2.forEach(([k, v, tt], i) => {
|
| 823 |
+
const a = sstep(tt, tt + 1, lt), y = ty + (80 + i * 64) * u;
|
| 824 |
+
text(ctx, k, tx - 20 * u, y, 28 * u, '#c9d6ff', 'right', a, SANS, 500);
|
| 825 |
+
text(ctx, v, tx + 20 * u, y, 32 * u, '#ffe1a0', 'left', a, SERIF, 800);
|
| 826 |
+
});
|
| 827 |
+
const words = [['灵动', '#9fe0ff'], ['聪慧', '#ffd08a'], ['妙语连珠', '#ffb3e0']];
|
| 828 |
words.forEach(([w, col], i) => {
|
| 829 |
+
const a = sstep(L[3] + 2.2 + i * .8, L[3] + 3 + i * .8, lt);
|
| 830 |
+
const x = tx + (i - 1) * (port ? 260 : 240) * u, y = ty + (port ? 290 : 300) * u + Math.sin(lt * 1.5 + i * 2) * 8 * u;
|
| 831 |
+
ctx.save(); ctx.globalAlpha = a; ctx.translate(x, y); const k = backOut(a); ctx.scale(k, k);
|
| 832 |
+
const bw = (w.length > 2 ? 190 : 140) * u;
|
| 833 |
+
rrect(ctx, -bw / 2, -38 * u, bw, 76 * u, 38 * u); ctx.fillStyle = hexA(col, .14); ctx.fill(); ctx.strokeStyle = col; ctx.lineWidth = 2 * u; ctx.shadowColor = col; ctx.shadowBlur = 16 * u; ctx.stroke(); ctx.restore();
|
| 834 |
+
text(ctx, w, x, y, 34 * u, col, 'center', a, SERIF, 800);
|
| 835 |
});
|
| 836 |
+
text(ctx, '—— 千百年来,人们写给双子座的赞美', tx, ty + (port ? 380 : 390) * u, 24 * u, '#d9c9a6', 'center', sstep(L[3] + 5, L[3] + 6, lt), SERIF, 600);
|
| 837 |
+
goldDust(ctx, W, H, lt, culture * .8, u, 40, 7);
|
| 838 |
}
|
| 839 |
};
|
| 840 |
|
| 841 |
+
/* ---------------- 荣耀元素 ---------------- */
|
| 842 |
+
function drawGlyph(ctx, gx, gy, s, alpha, u) {
|
| 843 |
+
if (alpha <= .003) return;
|
| 844 |
+
ctx.save(); ctx.globalAlpha = alpha; ctx.shadowColor = 'rgba(255,190,90,.85)'; ctx.shadowBlur = 40 * u;
|
| 845 |
+
ctx.strokeStyle = goldGrad(ctx, gx - s / 2, gy - s / 2, gx + s / 2, gy + s / 2); ctx.lineWidth = s * .07; ctx.lineCap = 'round';
|
| 846 |
+
const w = s * .5, h2 = s * .55;
|
| 847 |
+
ctx.beginPath(); ctx.moveTo(gx - w * .62, gy - h2 * .55); ctx.quadraticCurveTo(gx, gy - h2 * .35, gx + w * .62, gy - h2 * .55);
|
| 848 |
+
ctx.moveTo(gx - w * .62, gy + h2 * .55); ctx.quadraticCurveTo(gx, gy + h2 * .35, gx + w * .62, gy + h2 * .55);
|
| 849 |
+
ctx.moveTo(gx - w * .25, gy - h2 * .45); ctx.lineTo(gx - w * .25, gy + h2 * .45);
|
| 850 |
+
ctx.moveTo(gx + w * .25, gy - h2 * .45); ctx.lineTo(gx + w * .25, gy + h2 * .45); ctx.stroke();
|
| 851 |
+
ctx.restore();
|
| 852 |
+
}
|
| 853 |
+
function godRays(ctx, x, y, R, rot, alpha, n = 24) {
|
| 854 |
+
if (alpha <= .003) return;
|
| 855 |
+
ctx.save(); ctx.globalAlpha = alpha; ctx.globalCompositeOperation = 'lighter'; ctx.translate(x, y); ctx.rotate(rot);
|
| 856 |
+
const g = ctx.createRadialGradient(0, 0, 0, 0, 0, R); g.addColorStop(0, 'rgba(255,214,140,.55)'); g.addColorStop(.5, 'rgba(255,190,90,.12)'); g.addColorStop(1, 'rgba(255,190,90,0)');
|
| 857 |
+
ctx.fillStyle = g;
|
| 858 |
+
for (let i = 0; i < n; i++) { const a = i / n * TAU, w = (i % 2 ? .035 : .07); ctx.beginPath(); ctx.moveTo(0, 0); ctx.arc(0, 0, R * (i % 2 ? .8 : 1), a - w, a + w); ctx.closePath(); ctx.fill(); }
|
| 859 |
+
ctx.restore();
|
| 860 |
+
}
|
| 861 |
+
function goldDust(ctx, W, H, t, alpha, u, n = 60, seed = 11) {
|
| 862 |
+
if (alpha <= .003) return;
|
| 863 |
+
const r = rng(seed);
|
| 864 |
+
for (let i = 0; i < n; i++) {
|
| 865 |
+
const x0 = r() * W, sp = .03 + r() * .06, ph = r(), y = H * (1.05 - ((ph + t * sp) % 1) * 1.1), x = x0 + Math.sin(t * .8 + i) * 20 * u;
|
| 866 |
+
drawStar(ctx, x, y, (1.5 + r() * 3) * u, r() > .5 ? '#ffd98e' : '#fff1c8', alpha * (.4 + .6 * Math.sin(t * 3 + i) ** 2));
|
| 867 |
+
}
|
| 868 |
+
}
|
| 869 |
+
function laurel(ctx, cx, cy, R, alpha, u, grow = 1) {
|
| 870 |
+
if (alpha <= .003) return;
|
| 871 |
+
ctx.save(); ctx.globalAlpha = alpha; ctx.fillStyle = goldGrad(ctx, cx - R, cy - R, cx + R, cy + R); ctx.shadowColor = 'rgba(255,190,90,.6)'; ctx.shadowBlur = 10 * u;
|
| 872 |
+
for (const side of [-1, 1]) {
|
| 873 |
+
const N = 11;
|
| 874 |
+
for (let i = 0; i < N * grow; i++) {
|
| 875 |
+
const a = Math.PI / 2 + side * (.35 + i / N * 2.0), x = cx + Math.cos(a) * R, y = cy + Math.sin(a) * R;
|
| 876 |
+
for (const off of [-1, 1]) {
|
| 877 |
+
ctx.save(); ctx.translate(x, y); ctx.rotate(a + side * Math.PI / 2 + off * .55 * side);
|
| 878 |
+
ctx.beginPath(); ctx.ellipse(0, off * R * .05, R * .075, R * .03, 0, 0, TAU); ctx.fill(); ctx.restore();
|
| 879 |
+
}
|
| 880 |
+
}
|
| 881 |
+
}
|
| 882 |
+
ctx.restore();
|
| 883 |
+
}
|
| 884 |
+
function drawEmblem(ctx, cx, cy, R, lt, a, u, t) {
|
| 885 |
+
if (a <= .003) return;
|
| 886 |
+
godRays(ctx, cx, cy, R * 3, lt * .06, a * .7, 28);
|
| 887 |
+
drawStar(ctx, cx, cy, R * .9, '#ffbf63', a * .45);
|
| 888 |
+
ctx.save(); ctx.globalAlpha = a;
|
| 889 |
+
// 底盘
|
| 890 |
+
const bg = ctx.createRadialGradient(cx, cy - R * .3, R * .1, cx, cy, R);
|
| 891 |
+
bg.addColorStop(0, '#26306b'); bg.addColorStop(.7, '#121638'); bg.addColorStop(1, '#0a0c22');
|
| 892 |
+
ctx.fillStyle = bg; ctx.beginPath(); ctx.arc(cx, cy, R, 0, TAU); ctx.fill();
|
| 893 |
+
// 双金环
|
| 894 |
+
const gg = goldGrad(ctx, cx - R, cy - R, cx + R, cy + R);
|
| 895 |
+
ctx.strokeStyle = gg; ctx.shadowColor = 'rgba(255,190,90,.8)'; ctx.shadowBlur = 20 * u;
|
| 896 |
+
ctx.lineWidth = R * .06; ctx.beginPath(); ctx.arc(cx, cy, R, 0, TAU); ctx.stroke();
|
| 897 |
+
ctx.lineWidth = R * .015; ctx.beginPath(); ctx.arc(cx, cy, R * .86, 0, TAU); ctx.stroke();
|
| 898 |
+
// 刻度(反向旋转)
|
| 899 |
+
ctx.shadowBlur = 0; ctx.lineWidth = R * .012;
|
| 900 |
+
for (let i = 0; i < 72; i++) { const ang = i / 72 * TAU - lt * .05, l = i % 6 === 0 ? .08 : .04; ctx.beginPath(); ctx.moveTo(cx + Math.cos(ang) * R * .9, cy + Math.sin(ang) * R * .9); ctx.lineTo(cx + Math.cos(ang) * R * (.9 + l * .7), cy + Math.sin(ang) * R * (.9 + l * .7)); ctx.stroke(); }
|
| 901 |
+
ctx.restore();
|
| 902 |
+
// 内部星座
|
| 903 |
+
const view = { cx: 1, cy: -1.5, s: R * .03, ox: cx, oy: cy - R * .02 };
|
| 904 |
+
ctx.save(); ctx.beginPath(); ctx.arc(cx, cy, R * .84, 0, TAU); ctx.clip();
|
| 905 |
+
drawGlyph(ctx, cx, cy, R * 1.1, a * .16, u);
|
| 906 |
+
drawLines(ctx, view, GEM_LINES, 1, 'rgba(255,224,170,.95)', R * .012, a);
|
| 907 |
+
drawStarSet(ctx, view, GEM_KEYS, t, u * R / 300, a, { castor: 1.5, pollux: 1.6 });
|
| 908 |
+
ctx.restore();
|
| 909 |
+
// 环绕星光
|
| 910 |
+
for (let i = 0; i < 2; i++) { const ang = lt * .6 + i * Math.PI; drawStar(ctx, cx + Math.cos(ang) * R, cy + Math.sin(ang) * R, R * .045, i ? '#ffc985' : '#e3ecff', a, 1); }
|
| 911 |
+
// 桂冠
|
| 912 |
+
laurel(ctx, cx, cy, R * 1.16, a, u, clamp(a * 1.2));
|
| 913 |
+
// 绶带
|
| 914 |
+
const by = cy + R * 1.02, bw = R * 1.5, bh = R * .26;
|
| 915 |
+
ctx.save(); ctx.globalAlpha = a;
|
| 916 |
+
ctx.fillStyle = '#7a1f2b';
|
| 917 |
+
for (const sd of [-1, 1]) { ctx.beginPath(); ctx.moveTo(cx + sd * bw * .42, by - bh * .3); ctx.lineTo(cx + sd * bw * .66, by - bh * .1); ctx.lineTo(cx + sd * bw * .58, by + bh * .35); ctx.lineTo(cx + sd * bw * .66, by + bh * .8); ctx.lineTo(cx + sd * bw * .38, by + bh * .6); ctx.closePath(); ctx.fill(); }
|
| 918 |
+
const rg = ctx.createLinearGradient(0, by - bh / 2, 0, by + bh / 2); rg.addColorStop(0, '#c23a4a'); rg.addColorStop(1, '#8e2232');
|
| 919 |
+
ctx.fillStyle = rg; ctx.beginPath(); ctx.moveTo(cx - bw / 2, by - bh / 2); ctx.quadraticCurveTo(cx, by - bh * .9, cx + bw / 2, by - bh / 2); ctx.lineTo(cx + bw / 2, by + bh / 2); ctx.quadraticCurveTo(cx, by + bh * .1, cx - bw / 2, by + bh / 2); ctx.closePath(); ctx.fill();
|
| 920 |
+
ctx.strokeStyle = goldGrad(ctx, cx - bw / 2, by, cx + bw / 2, by); ctx.lineWidth = 2.5 * u; ctx.stroke();
|
| 921 |
+
ctx.restore();
|
| 922 |
+
text(ctx, 'GEMINI · 双 子 座', cx, by - bh * .12, bh * .42, '#fff0c8', 'center', a, SERIF, 900);
|
| 923 |
+
}
|
| 924 |
+
|
| 925 |
+
// 9. 尾声 · 荣耀时刻
|
| 926 |
SC.outro = (ctx, lt, D, W, H, L, t) => {
|
| 927 |
const { u, port } = layout(W, H);
|
| 928 |
+
const emb = sstep(L[2] - 1, L[2] + 1.2, lt);
|
| 929 |
+
const view = { cx: 1, cy: -1.5, s: lerp(22, 26, easeIO(clamp(lt / L[2]))) * u * (port ? 1.15 : 1), ox: W / 2, oy: H * (port ? .34 : .40) - emb * H * .1 };
|
| 930 |
+
const a = sstep(0, 1.5, lt) * (1 - emb);
|
| 931 |
drawLines(ctx, view, GEM_LINES, 1, 'rgba(255,190,110,.22)', 24 * u, a * .6);
|
| 932 |
drawLines(ctx, view, GEM_LINES, sstep(0, 3, lt), 'rgba(255,230,180,.95)', 2.6 * u, a);
|
| 933 |
+
drawStarSet(ctx, view, GEM_KEYS, t, u, a, { castor: 1.4 + sstep(L[1], L[1] + 1, lt) * .8, pollux: 1.5 + sstep(L[1], L[1] + 1, lt) * .8 });
|
| 934 |
+
// 回顾标签
|
| 935 |
+
const icons = [['兄弟情', '#ffe1a0'], ['流星雨', '#cfe0ff'], ['六星家族', '#ffd0a0']];
|
| 936 |
icons.forEach(([s, col], i) => chip(ctx, s, W / 2 + (i - 1) * (port ? 250 : 260) * u, H * (port ? .62 : .74), 28 * u, sstep(.8 + i * .9, 1.8 + i * .9, lt) * (1 - sstep(L[1] - .5, L[1] + .5, lt)), col));
|
| 937 |
+
// 为你点亮:星光洒向仰望者
|
| 938 |
+
const you = sstep(L[1], L[1] + 1.2, lt) * (1 - emb);
|
| 939 |
+
if (you > 0) {
|
| 940 |
+
const hy = H * (port ? .7 : .8), px = W / 2, py = hy - 10 * u;
|
| 941 |
+
ctx.save(); ctx.globalAlpha = you; const hg = ctx.createLinearGradient(0, hy - 40 * u, 0, H); hg.addColorStop(0, 'rgba(10,12,30,0)'); hg.addColorStop(.3, '#070816'); hg.addColorStop(1, '#030308');
|
| 942 |
+
ctx.fillStyle = hg; ctx.beginPath(); ctx.moveTo(0, H); for (let x = 0; x <= W; x += 20 * u) ctx.lineTo(x, hy + Math.sin(x / W * 4 + 1) * 18 * u); ctx.lineTo(W, H); ctx.fill(); ctx.restore();
|
| 943 |
+
['castor', 'pollux'].forEach((k, i) => {
|
| 944 |
+
const [sx, sy] = P(view, k); const pr = easeOut(sstep(L[1] + .5 + i * .4, L[1] + 3 + i * .4, lt));
|
| 945 |
+
const g = ctx.createLinearGradient(sx, sy, px, py); const col = i ? '255,201,133' : '227,236,255';
|
| 946 |
+
g.addColorStop(0, `rgba(${col},.8)`); g.addColorStop(1, `rgba(${col},0)`);
|
| 947 |
+
ctx.save(); ctx.globalAlpha = you * .8; ctx.globalCompositeOperation = 'lighter'; ctx.strokeStyle = g; ctx.lineWidth = 3 * u; ctx.beginPath(); ctx.moveTo(sx, sy); ctx.lineTo(lerp(sx, px, pr), lerp(sy, py - 60 * u, pr)); ctx.stroke(); ctx.restore();
|
| 948 |
+
});
|
| 949 |
+
drawStar(ctx, px, py - 40 * u, 40 * u, '#ffd98e', you * sstep(L[1] + 2.5, L[1] + 3.5, lt) * .7);
|
| 950 |
+
figure(ctx, px, py + 30 * u, 90 * u, { color: '#ffe6b0', alpha: you, arm: .7, glow: .8, fill: 'rgba(255,214,140,.15)', time: t });
|
| 951 |
+
chip(ctx, '为你点亮', px, py + 80 * u, 26 * u, you * sstep(L[1] + 3, L[1] + 4, lt));
|
| 952 |
+
}
|
| 953 |
+
// 荣耀徽章
|
| 954 |
+
if (emb > 0) {
|
| 955 |
+
const R = (port ? 250 : 220) * u * lerp(.6, 1, easeOut(emb));
|
| 956 |
+
const cx = W / 2, cy = H * (port ? .32 : .37);
|
| 957 |
+
const ex = port ? cx : lerp(W / 2, W * .32, sstep(L[2] + 1, L[2] + 2.5, lt) * (1 - sstep(L[3] - .5, L[3] + 1, lt)));
|
| 958 |
+
drawEmblem(ctx, ex, cy, R, lt, emb, u, t);
|
| 959 |
+
goldDust(ctx, W, H, lt, emb, u, 70, 21);
|
| 960 |
+
// 三块荣誉铭牌
|
| 961 |
+
const plaques = [['好奇', '探索世界的勇气'], ['多面', '丰盈闪耀的灵魂'], ['陪伴', '永不分离的守候']];
|
| 962 |
+
const pv = 1 - sstep(L[3] - .5, L[3] + .8, lt);
|
| 963 |
+
plaques.forEach(([k, v], i) => {
|
| 964 |
+
const tt = L[2] + 1.5 + i * 2.6, pa = sstep(tt, tt + .8, lt) * pv;
|
| 965 |
+
if (pa <= 0) return;
|
| 966 |
+
const pw = (port ? 640 : 420) * u, ph = (port ? 88 : 96) * u;
|
| 967 |
+
const xx = port ? W / 2 - pw / 2 : W * .72 - pw / 2, y = port ? H * .535 + i * ph * 1.22 : H * (.24 + i * .15);
|
| 968 |
+
const w2 = pw;
|
| 969 |
+
ctx.save(); ctx.globalAlpha = pa; ctx.translate((1 - pa) * 60 * u, 0);
|
| 970 |
+
rrect(ctx, xx, y, w2, ph, 18 * u); const pg = ctx.createLinearGradient(xx, y, xx + w2, y + ph); pg.addColorStop(0, 'rgba(60,40,20,.85)'); pg.addColorStop(1, 'rgba(25,20,50,.85)');
|
| 971 |
+
ctx.fillStyle = pg; ctx.fill(); ctx.strokeStyle = goldGrad(ctx, xx, y, xx + w2, y + ph); ctx.lineWidth = 2 * u; ctx.shadowColor = 'rgba(255,190,90,.6)'; ctx.shadowBlur = 18 * u; ctx.stroke(); ctx.restore();
|
| 972 |
+
if (port) {
|
| 973 |
+
text(ctx, k, xx + 40 * u + (1 - pa) * 60 * u, y + ph / 2, 42 * u, '#ffe1a0', 'left', pa, SERIF, 900, 'rgba(255,190,90,.6)');
|
| 974 |
+
text(ctx, v, xx + 160 * u + (1 - pa) * 60 * u, y + ph / 2, 30 * u, '#f1e6cc', 'left', pa, SANS, 500);
|
| 975 |
+
} else {
|
| 976 |
+
text(ctx, k, xx + 36 * u + (1 - pa) * 60 * u, y + ph / 2, 44 * u, '#ffe1a0', 'left', pa, SERIF, 900, 'rgba(255,190,90,.6)');
|
| 977 |
+
text(ctx, v, xx + 150 * u + (1 - pa) * 60 * u, y + ph / 2, 28 * u, '#f1e6cc', 'left', pa, SANS, 500);
|
| 978 |
+
}
|
| 979 |
+
});
|
| 980 |
+
}
|
| 981 |
// 流星
|
| 982 |
const r = rng(3);
|
| 983 |
+
for (let i = 0; i < 10; i++) {
|
| 984 |
+
const t0 = 2 + i * 3.4 + r(), age = lt - t0; if (age < 0 || age > .8) continue;
|
| 985 |
+
const x = W * (.1 + r() * .6), y = H * (.05 + r() * .15), k = age / .8, len = 220 * u;
|
| 986 |
const x1 = x + k * 300 * u, y1 = y + k * 150 * u;
|
| 987 |
+
const g = ctx.createLinearGradient(x1 - len, y1 - len / 2, x1, y1); g.addColorStop(0, 'rgba(255,255,255,0)'); g.addColorStop(1, `rgba(255,240,210,${Math.sin(k * Math.PI)})`);
|
| 988 |
ctx.strokeStyle = g; ctx.lineWidth = 2.5 * u; ctx.beginPath(); ctx.moveTo(x1 - len * .9, y1 - len * .45); ctx.lineTo(x1, y1); ctx.stroke();
|
| 989 |
}
|
| 990 |
+
// 结尾大字
|
| 991 |
+
const e = sstep(L[4] - .3, L[4] + 1.5, lt);
|
| 992 |
if (e > 0) {
|
| 993 |
+
const ty = H * (port ? .68 : .75), size = (port ? 96 : 92) * u;
|
| 994 |
ctx.save(); ctx.globalAlpha = e; ctx.font = `900 ${size}px ${SERIF}`; ctx.textAlign = 'center'; ctx.textBaseline = 'middle';
|
| 995 |
+
ctx.shadowColor = 'rgba(255,170,70,.9)'; ctx.shadowBlur = 36 * u; ctx.fillStyle = goldGrad(ctx, W / 2 - size * 3, ty, W / 2 + size * 3, ty);
|
| 996 |
+
ctx.fillText('属于你的光', W / 2, ty); ctx.restore();
|
| 997 |
+
text(ctx, '致 每 一 位 双 子 座', W / 2, ty + size * .85, 32 * u, '#ffe6b0', 'center', e, SERIF, 700);
|
| 998 |
}
|
| 999 |
// 最后淡出
|
| 1000 |
const out = sstep(D - 2.2, D, lt);
|
| 1001 |
if (out > 0) { ctx.fillStyle = `rgba(0,0,0,${out})`; ctx.fillRect(0, 0, W, H); }
|
| 1002 |
};
|
| 1003 |
|
| 1004 |
+
const CHAPTERS = { intro: '序章', find: '怎样找到它', myth: '神话 · 孪生兄弟', castor: '北河二 · 六星家族', pollux: '北河三 · 橙色巨星', meteor: '双子座流星雨', discover: '星空里的发现', zodiac: '黄道与星座文化', outro: '尾声 · 致双子座' };
|
| 1005 |
const CAMS = { intro: [0, 0], find: [1, .4], myth: [2, .8], castor: [3, 1.1], pollux: [4, 1.5], meteor: [5, 2.1], discover: [6, 2.5], zodiac: [7, 2.9], outro: [8, 3.3] };
|
| 1006 |
|
| 1007 |
/* ---------------- 主渲染 ---------------- */
|
gemini-stars/timeline.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
// 由 tools/make_voice.py 自动生成,请勿手改
|
| 2 |
export const TIMELINE = {
|
| 3 |
-
"duration":
|
| 4 |
"scenes": [
|
| 5 |
{
|
| 6 |
"id": "intro",
|
|
@@ -201,43 +201,61 @@ export const TIMELINE = {
|
|
| 201 |
},
|
| 202 |
{
|
| 203 |
"file": "audio/v25.mp3",
|
| 204 |
-
"text": "而在
|
| 205 |
"start": 175.95,
|
| 206 |
-
"end":
|
| 207 |
},
|
| 208 |
{
|
| 209 |
"file": "audio/v26.mp3",
|
| 210 |
-
"text": "人们
|
| 211 |
-
"start":
|
| 212 |
-
"end":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 213 |
}
|
| 214 |
],
|
| 215 |
-
"end":
|
| 216 |
},
|
| 217 |
{
|
| 218 |
"id": "outro",
|
| 219 |
-
"start":
|
| 220 |
"lines": [
|
| 221 |
{
|
| 222 |
-
"file": "audio/
|
| 223 |
"text": "两颗星,一段兄弟情,一场流星雨,和一个装满秘密的六星家族。",
|
| 224 |
-
"start":
|
| 225 |
-
"end":
|
| 226 |
},
|
| 227 |
{
|
| 228 |
-
"file": "audio/
|
| 229 |
-
"text": "
|
| 230 |
-
"start":
|
| 231 |
-
"end":
|
| 232 |
},
|
| 233 |
{
|
| 234 |
-
"file": "audio/
|
| 235 |
-
"text": "
|
| 236 |
-
"start":
|
| 237 |
-
"end":
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
}
|
| 239 |
],
|
| 240 |
-
"end":
|
| 241 |
}
|
| 242 |
]
|
| 243 |
};
|
|
|
|
| 1 |
// 由 tools/make_voice.py 自动生成,请勿手改
|
| 2 |
export const TIMELINE = {
|
| 3 |
+
"duration": 249.25,
|
| 4 |
"scenes": [
|
| 5 |
{
|
| 6 |
"id": "intro",
|
|
|
|
| 201 |
},
|
| 202 |
{
|
| 203 |
"file": "audio/v25.mp3",
|
| 204 |
+
"text": "而在流传千年的星座文化里,五月二十一日到六月二十一日出生的人,被称作双子座。",
|
| 205 |
"start": 175.95,
|
| 206 |
+
"end": 184.18
|
| 207 |
},
|
| 208 |
{
|
| 209 |
"file": "audio/v26.mp3",
|
| 210 |
+
"text": "人们说,双子座的心里住着两颗星:一颗是好奇,让你永远对世界充满热情;一颗是温柔,让你懂得倾听与陪伴。",
|
| 211 |
+
"start": 184.56,
|
| 212 |
+
"end": 195.96
|
| 213 |
+
},
|
| 214 |
+
{
|
| 215 |
+
"file": "audio/v27.mp3",
|
| 216 |
+
"text": "风象星座,水星守护。灵动、聪慧、妙语连珠——这是千百年来,人们写给双子座的赞美。",
|
| 217 |
+
"start": 196.34,
|
| 218 |
+
"end": 205.92
|
| 219 |
}
|
| 220 |
],
|
| 221 |
+
"end": 206.86
|
| 222 |
},
|
| 223 |
{
|
| 224 |
"id": "outro",
|
| 225 |
+
"start": 206.86,
|
| 226 |
"lines": [
|
| 227 |
{
|
| 228 |
+
"file": "audio/v28.mp3",
|
| 229 |
"text": "两颗星,一段兄弟情,一场流星雨,和一个装满秘密的六星家族。",
|
| 230 |
+
"start": 207.7,
|
| 231 |
+
"end": 214.42
|
| 232 |
},
|
| 233 |
{
|
| 234 |
+
"file": "audio/v29.mp3",
|
| 235 |
+
"text": "如果你是双子座,请记得:北河二与北河三,从远古起,就在冬夜里为你点亮。",
|
| 236 |
+
"start": 214.8,
|
| 237 |
+
"end": 222.58
|
| 238 |
},
|
| 239 |
{
|
| 240 |
+
"file": "audio/v30.mp3",
|
| 241 |
+
"text": "你的好奇,是探索世界的勇气;你的多面,是丰盈闪耀的灵魂;你的陪伴,就像那对永不分离的兄弟。",
|
| 242 |
+
"start": 222.96,
|
| 243 |
+
"end": 232.85
|
| 244 |
+
},
|
| 245 |
+
{
|
| 246 |
+
"file": "audio/v31.mp3",
|
| 247 |
+
"text": "下一个晴朗的冬夜,抬头找一找那对并肩的星星。",
|
| 248 |
+
"start": 233.23,
|
| 249 |
+
"end": 238.27
|
| 250 |
+
},
|
| 251 |
+
{
|
| 252 |
+
"file": "audio/v32.mp3",
|
| 253 |
+
"text": "那是属于你的星座,也是属于你的光。",
|
| 254 |
+
"start": 238.65,
|
| 255 |
+
"end": 242.37
|
| 256 |
}
|
| 257 |
],
|
| 258 |
+
"end": 249.25
|
| 259 |
}
|
| 260 |
]
|
| 261 |
};
|
gemini-stars/tools/make_voice.py
CHANGED
|
@@ -43,15 +43,18 @@ SCENES = [
|
|
| 43 |
"一九三零年,汤博在双子座天区的照片里,找到了冥王星。"]),
|
| 44 |
("zodiac", 1.2, [
|
| 45 |
"双子座也是黄道星座之一。每年六月下旬到七月下旬,太阳会从它的天区穿过。",
|
| 46 |
-
"而在
|
| 47 |
-
"人们
|
| 48 |
-
|
|
|
|
| 49 |
"两颗星,一段兄弟情,一场流星雨,和一个装满秘密的六星家族。",
|
| 50 |
-
"
|
| 51 |
-
"
|
|
|
|
|
|
|
| 52 |
]
|
| 53 |
GAP = 0.38
|
| 54 |
-
TAIL =
|
| 55 |
FF = imageio_ffmpeg.get_ffmpeg_exe()
|
| 56 |
|
| 57 |
def dur(path):
|
|
|
|
| 43 |
"一九三零年,汤博在双子座天区的照片里,找到了冥王星。"]),
|
| 44 |
("zodiac", 1.2, [
|
| 45 |
"双子座也是黄道星座之一。每年六月下旬到七月下旬,太阳会从它的天区穿过。",
|
| 46 |
+
"而在流传千年的星座文化里,五月二十一日到六月二十一日出生的人,被称作双子座。",
|
| 47 |
+
"人们说,双子座的心里住着两颗星:一颗是好奇,让你永远对世界充满热情;一颗是温柔,让你懂得倾听与陪伴。",
|
| 48 |
+
"风象星座,水星守护。灵动、聪慧、妙语连珠——这是千百年来,人们写给双子座的赞美。"]),
|
| 49 |
+
("outro", 1.4, [
|
| 50 |
"两颗星,一段兄弟情,一场流星雨,和一个装满秘密的六星家族。",
|
| 51 |
+
"如果你是双子座,请记得:北河二与北河三,从远古起,就在冬夜里为你点亮。",
|
| 52 |
+
"你的好奇,是探索世界的勇气;你的多面,是丰盈闪耀的灵魂;你的陪伴,就像那对永不分离的兄弟。",
|
| 53 |
+
"下一个晴朗的冬夜,抬头找一找那对并肩的星星。",
|
| 54 |
+
"那是属于你的星座,也是属于你的光。"]),
|
| 55 |
]
|
| 56 |
GAP = 0.38
|
| 57 |
+
TAIL = 6.5
|
| 58 |
FF = imageio_ffmpeg.get_ffmpeg_exe()
|
| 59 |
|
| 60 |
def dur(path):
|
index.html
CHANGED
|
@@ -12,7 +12,7 @@ a.card div{padding:14px 16px}a.card b{font-size:19px}a.card span{display:block;o
|
|
| 12 |
</style></head><body>
|
| 13 |
<h1>知识动画工作室</h1><p>网页即播 · 浏览器本地导出 MP4 · 横屏 B站 / 竖屏抖音</p>
|
| 14 |
<div class="grid">
|
| 15 |
-
<a class="card" href="gemini-stars/index.html"><img src="gemini-stars/covers/cover-bili-16x9.jpg" alt="双子座 · 星河里的一对兄弟" onerror="this.style.visibility='hidden'"><div><b>♊ 双子座:星河里的一对兄弟</b><span>星座动画 · 全新制作 · 深空金线星图 · 约
|
| 16 |
<a class="card" href="taurus/index.html"><img src="taurus/covers/cover-bili-16x9.jpg" alt="金牛座 · 慢慢来,也能抵达美好" onerror="this.style.visibility='hidden'"><div><b>♉ 金牛座:慢慢来,也能抵达美好</b><span>星座动画 · 全新制作 · 新艺术鎏金花卉 · 约 4 分 10 秒 · 鎏金珍藏卡 · 横竖屏 · 24/30/60fps 导出</span></div></a>
|
| 17 |
<a class="card" href="aries/index.html"><img src="aries/covers/cover-bilibili-16x9.jpg" alt="白羊座 · 春天从这里出发" onerror="this.style.visibility='hidden'"><div><b>♈ 白羊座:春天从这里出发</b><span>星座动画 · 全新制作 · 烈焰金红 · 约 3 分 33 秒 · 专属荣耀铭牌 · 横竖屏 · 24/30/60fps 导出</span></div></a>
|
| 18 |
<a class="card" href="libra-scales/index.html"><img src="libra-scales/covers/cover-landscape.jpg" alt="天秤座 · 星空中的一杆秤" onerror="this.style.visibility='hidden'"><div><b>♎ 天秤座:星空中的一杆秤</b><span>星座动画解说 · 全新制作 · 金色星图风 · 约 3 分 40 秒 · 横竖屏 · 24/30/60fps 导出</span></div></a>
|
|
|
|
| 12 |
</style></head><body>
|
| 13 |
<h1>知识动画工作室</h1><p>网页即播 · 浏览器本地导出 MP4 · 横屏 B站 / 竖屏抖音</p>
|
| 14 |
<div class="grid">
|
| 15 |
+
<a class="card" href="gemini-stars/index.html"><img src="gemini-stars/covers/cover-bili-16x9.jpg" alt="双子座 · 星河里的一对兄弟" onerror="this.style.visibility='hidden'"><div><b>♊ 双子座:星河里的一对兄弟</b><span>星座动画 · 全新制作 · 深空金线星图 · 约 4 分 09 秒 · 双子荣耀徽章 · 配乐音效旁白 · 横竖屏 · 24/30/60fps 导出 · 多平台封面文案</span></div></a>
|
| 16 |
<a class="card" href="taurus/index.html"><img src="taurus/covers/cover-bili-16x9.jpg" alt="金牛座 · 慢慢来,也能抵达美好" onerror="this.style.visibility='hidden'"><div><b>♉ 金牛座:慢慢来,也能抵达美好</b><span>星座动画 · 全新制作 · 新艺术鎏金花卉 · 约 4 分 10 秒 · 鎏金珍藏卡 · 横竖屏 · 24/30/60fps 导出</span></div></a>
|
| 17 |
<a class="card" href="aries/index.html"><img src="aries/covers/cover-bilibili-16x9.jpg" alt="白羊座 · 春天从这里出发" onerror="this.style.visibility='hidden'"><div><b>♈ 白羊座:春天从这里出发</b><span>星座动画 · 全新制作 · 烈焰金红 · 约 3 分 33 秒 · 专属荣耀铭牌 · 横竖屏 · 24/30/60fps 导出</span></div></a>
|
| 18 |
<a class="card" href="libra-scales/index.html"><img src="libra-scales/covers/cover-landscape.jpg" alt="天秤座 · 星空中的一杆秤" onerror="this.style.visibility='hidden'"><div><b>♎ 天秤座:星空中的一杆秤</b><span>星座动画解说 · 全新制作 · 金色星图风 · 约 3 分 40 秒 · 横竖屏 · 24/30/60fps 导出</span></div></a>
|