diff --git a/SKILL.md b/SKILL.md index 7d3641d..677b9ea 100644 --- a/SKILL.md +++ b/SKILL.md @@ -167,6 +167,34 @@ curl -A "Mozilla/5.0" -L "" -o assets/-brand/product-hero - 产品官方 Twitter/X 的发布截图(常是最新版本) - 用户有账号时,直接截屏真实产品界面 +**3.4 · 素材质量门槛「5-10-2-8」原则(铁律)** + +> **Logo 的规则不同于其他素材**。Logo 有就必须用(没有就停下问用户);其他素材(产品图/UI/参考图/配图)遵循「5-10-2-8」质量门槛。 +> +> 2026-04-20 花叔原话:「我们的原则是搜索 5 轮,找到 10 个素材,选择 2 个好的。每个需要评分 8/10 以上,宁可少一些,也不为了完成任务滥竽充数。」 + +| 维度 | 标准 | 反模式 | +|---|---|---| +| **5 轮搜索** | 多渠道交叉搜(官网 / press kit / 官方社媒 / YouTube 截帧 / Wikimedia / 用户账号截屏),不是一轮抓前 2 个就停 | 第一页结果直接用 | +| **10 个候选** | 至少凑 10 个备选才开始筛 | 只抓 2 个,没得选 | +| **选 2 个好的** | 从 10 个里精选 2 个作为最终素材 | 全都用 = 视觉过载 + 品位稀释 | +| **每个 8/10 分以上** | 不够 8 分**宁可不用**,用诚实 placeholder(灰块+文字标签)或 AI 生成(nano-banana-pro 以官方参考为基底)| 凑数 7 分素材进 brand-spec.md | + +**8/10 评分维度**(打分时记录在 `brand-spec.md`): + +1. **分辨率** · ≥2000px(印刷/大屏场景 ≥3000px) +2. **版权清晰度** · 官方来源 > 公共领域 > 免费素材 > 疑似盗图(疑似盗图直接 0 分) +3. **与品牌气质契合度** · 和 brand-spec.md 里的「气质关键词」一致 +4. **光线/构图/风格一致性** · 2 个素材放一起不打架 +5. **独立叙事能力** · 能单独表达一个叙事角色(不是装饰) + +**为什么这个门槛是铁律**: +- 花叔的哲学:**宁缺毋滥**。滥竽充数的素材比没有更糟——污染视觉品味、传递「不专业」信号 +- **「一个细节做到 120%,其他做到 80%」的量化版**:8 分是"其他 80%" 的底线,真正 hero 素材要 9-10 分 +- 消费者看作品时,每一个视觉元素都在**积分或扣分**。7 分素材 = 扣分项,不如留空 + +**Logo 例外**(重申):有就必须用,不适用「5-10-2-8」。因为 logo 不是「多选一」问题,而是「识别度根基」问题——就算 logo 本身只有 6 分,也比没有 logo 强 10 倍。 + ##### Step 4 · 验证 + 提取(不只是 grep 色值) | 资产 | 验证动作 | @@ -601,7 +629,15 @@ Screen 组件接 callback props(`onEnter`、`onClose`、`onTabChange`、`onOpe 7. **验证**:用Playwright截图(见 `references/verification.md`),检查控制台错误,发给用户。 🛑 **检查点4:交付前自己肉眼过一遍浏览器**。AI写的代码经常有interaction bug。 8. **总结**:极简,只说caveats和next steps。 -9. **(可选)导出视频**:如果是动画HTML,用户若提「导出/MP4/GIF/60fps」,按 `references/video-export.md` 走:`scripts/render-video.js` 录 25fps MP4 → `scripts/convert-formats.sh` 派生 60fps MP4 + palette 优化 GIF → `scripts/add-music.sh` 加 BGM(6 首场景化配乐,按 `--mood=tech/ad/educational/tutorial` 选)。 +9. **(默认)导出视频 · 必带 SFX + BGM**:动画 HTML 的**默认交付形态是带音频的 MP4**,不是纯画面。无声版本等于半成品——用户潜意识感知「画在动但没声音响应」,廉价感的根源就在这里。流水线: + - `scripts/render-video.js` 录 25fps 纯画面 MP4(只是中间产物,**不是成品**) + - `scripts/convert-formats.sh` 派生 60fps MP4 + palette 优化 GIF(视平台需要) + - `scripts/add-music.sh` 加 BGM(6 首场景化配乐:tech/ad/educational/tutorial + alt 变体) + - SFX 按 `references/audio-design-rules.md` 设计 cue 清单(时间轴 + 音效类型),用 `assets/sfx//*.mp3` 37 个预制资源,按配方 A/B/C/D 选密度(发布 hero ≈ 6个/10s,工具演示 ≈ 0-2个/10s) + - **BGM + SFX 双轨制必须同时做**——只做 BGM 是 ⅓ 分完成度;SFX 占高频、BGM 占低频,频段隔离见 audio-design-rules.md 的 ffmpeg 模板 + - 交付前 `ffprobe -select_streams a` 确认有 audio stream,没有则不是成品 + - **跳过音频的条件**:用户明确说「不要音频」「纯画面」「我要自己配音」——否则默认带。 + - 参考完整流程见 `references/video-export.md` + `references/audio-design-rules.md` + `references/sfx-library.md`。 10. **(可选)专家评审**:用户若提「评审」「好不好看」「review」「打分」,或你对产出有疑问想主动质检,按 `references/critique-guide.md` 走 5 维度评审——哲学一致性 / 视觉层级 / 细节执行 / 功能性 / 创新性各 0-10 分,输出总评 + Keep(做得好的)+ Fix(严重程度 ⚠️致命 / ⚡重要 / 💡优化)+ Quick Wins(5 分钟能做的前 3 件事)。评审设计不评设计师。 **检查点原则**:碰到🛑就停下,明确告诉用户"我做了X,下一步打算Y,你确认吗?"然后真的**等**。不要说完自己就开始做。 diff --git a/assets/sfx/container/card-flip.mp3 b/assets/sfx/container/card-flip.mp3 new file mode 100644 index 0000000..ebfb492 Binary files /dev/null and b/assets/sfx/container/card-flip.mp3 differ diff --git a/assets/sfx/container/card-snap.mp3 b/assets/sfx/container/card-snap.mp3 new file mode 100644 index 0000000..91a3bf3 Binary files /dev/null and b/assets/sfx/container/card-snap.mp3 differ diff --git a/assets/sfx/container/modal-open.mp3 b/assets/sfx/container/modal-open.mp3 new file mode 100644 index 0000000..a7f96f7 Binary files /dev/null and b/assets/sfx/container/modal-open.mp3 differ diff --git a/assets/sfx/container/stack-collapse.mp3 b/assets/sfx/container/stack-collapse.mp3 new file mode 100644 index 0000000..3bac6f7 Binary files /dev/null and b/assets/sfx/container/stack-collapse.mp3 differ diff --git a/assets/sfx/feedback/achievement.mp3 b/assets/sfx/feedback/achievement.mp3 new file mode 100644 index 0000000..21536ea Binary files /dev/null and b/assets/sfx/feedback/achievement.mp3 differ diff --git a/assets/sfx/feedback/error-tone.mp3 b/assets/sfx/feedback/error-tone.mp3 new file mode 100644 index 0000000..1e3079c Binary files /dev/null and b/assets/sfx/feedback/error-tone.mp3 differ diff --git a/assets/sfx/feedback/notification-pop.mp3 b/assets/sfx/feedback/notification-pop.mp3 new file mode 100644 index 0000000..6d6cb4d Binary files /dev/null and b/assets/sfx/feedback/notification-pop.mp3 differ diff --git a/assets/sfx/feedback/success-chime.mp3 b/assets/sfx/feedback/success-chime.mp3 new file mode 100644 index 0000000..1c4049b Binary files /dev/null and b/assets/sfx/feedback/success-chime.mp3 differ diff --git a/assets/sfx/impact/brand-stamp.mp3 b/assets/sfx/impact/brand-stamp.mp3 new file mode 100644 index 0000000..e5320c0 Binary files /dev/null and b/assets/sfx/impact/brand-stamp.mp3 differ diff --git a/assets/sfx/impact/drop-thud.mp3 b/assets/sfx/impact/drop-thud.mp3 new file mode 100644 index 0000000..e81f8be Binary files /dev/null and b/assets/sfx/impact/drop-thud.mp3 differ diff --git a/assets/sfx/impact/logo-reveal-v2.mp3 b/assets/sfx/impact/logo-reveal-v2.mp3 new file mode 100644 index 0000000..84409a8 Binary files /dev/null and b/assets/sfx/impact/logo-reveal-v2.mp3 differ diff --git a/assets/sfx/impact/logo-reveal.mp3 b/assets/sfx/impact/logo-reveal.mp3 new file mode 100644 index 0000000..8bcb507 Binary files /dev/null and b/assets/sfx/impact/logo-reveal.mp3 differ diff --git a/assets/sfx/keyboard/delete-key.mp3 b/assets/sfx/keyboard/delete-key.mp3 new file mode 100644 index 0000000..b4f8058 Binary files /dev/null and b/assets/sfx/keyboard/delete-key.mp3 differ diff --git a/assets/sfx/keyboard/enter.mp3 b/assets/sfx/keyboard/enter.mp3 new file mode 100644 index 0000000..4cb1f37 Binary files /dev/null and b/assets/sfx/keyboard/enter.mp3 differ diff --git a/assets/sfx/keyboard/space-tap.mp3 b/assets/sfx/keyboard/space-tap.mp3 new file mode 100644 index 0000000..f3cce57 Binary files /dev/null and b/assets/sfx/keyboard/space-tap.mp3 differ diff --git a/assets/sfx/keyboard/type-fast.mp3 b/assets/sfx/keyboard/type-fast.mp3 new file mode 100644 index 0000000..a40d64d Binary files /dev/null and b/assets/sfx/keyboard/type-fast.mp3 differ diff --git a/assets/sfx/keyboard/type.mp3 b/assets/sfx/keyboard/type.mp3 new file mode 100644 index 0000000..7ea7c96 Binary files /dev/null and b/assets/sfx/keyboard/type.mp3 differ diff --git a/assets/sfx/magic/ai-process.mp3 b/assets/sfx/magic/ai-process.mp3 new file mode 100644 index 0000000..c109159 Binary files /dev/null and b/assets/sfx/magic/ai-process.mp3 differ diff --git a/assets/sfx/magic/sparkle.mp3 b/assets/sfx/magic/sparkle.mp3 new file mode 100644 index 0000000..adac6da Binary files /dev/null and b/assets/sfx/magic/sparkle.mp3 differ diff --git a/assets/sfx/magic/transform.mp3 b/assets/sfx/magic/transform.mp3 new file mode 100644 index 0000000..8bf267f Binary files /dev/null and b/assets/sfx/magic/transform.mp3 differ diff --git a/assets/sfx/progress/complete-done.mp3 b/assets/sfx/progress/complete-done.mp3 new file mode 100644 index 0000000..22383d7 Binary files /dev/null and b/assets/sfx/progress/complete-done.mp3 differ diff --git a/assets/sfx/progress/generate-start.mp3 b/assets/sfx/progress/generate-start.mp3 new file mode 100644 index 0000000..ff9bc73 Binary files /dev/null and b/assets/sfx/progress/generate-start.mp3 differ diff --git a/assets/sfx/progress/loading-tick.mp3 b/assets/sfx/progress/loading-tick.mp3 new file mode 100644 index 0000000..4bc31af Binary files /dev/null and b/assets/sfx/progress/loading-tick.mp3 differ diff --git a/assets/sfx/terminal/command-execute.mp3 b/assets/sfx/terminal/command-execute.mp3 new file mode 100644 index 0000000..07a10c8 Binary files /dev/null and b/assets/sfx/terminal/command-execute.mp3 differ diff --git a/assets/sfx/terminal/cursor-blink.mp3 b/assets/sfx/terminal/cursor-blink.mp3 new file mode 100644 index 0000000..6685098 Binary files /dev/null and b/assets/sfx/terminal/cursor-blink.mp3 differ diff --git a/assets/sfx/terminal/output-appear.mp3 b/assets/sfx/terminal/output-appear.mp3 new file mode 100644 index 0000000..71be2b1 Binary files /dev/null and b/assets/sfx/terminal/output-appear.mp3 differ diff --git a/assets/sfx/transition/dissolve.mp3 b/assets/sfx/transition/dissolve.mp3 new file mode 100644 index 0000000..a6046eb Binary files /dev/null and b/assets/sfx/transition/dissolve.mp3 differ diff --git a/assets/sfx/transition/slide-in.mp3 b/assets/sfx/transition/slide-in.mp3 new file mode 100644 index 0000000..595b221 Binary files /dev/null and b/assets/sfx/transition/slide-in.mp3 differ diff --git a/assets/sfx/transition/swipe-horizontal.mp3 b/assets/sfx/transition/swipe-horizontal.mp3 new file mode 100644 index 0000000..22beaf7 Binary files /dev/null and b/assets/sfx/transition/swipe-horizontal.mp3 differ diff --git a/assets/sfx/transition/whoosh-fast.mp3 b/assets/sfx/transition/whoosh-fast.mp3 new file mode 100644 index 0000000..65aaef0 Binary files /dev/null and b/assets/sfx/transition/whoosh-fast.mp3 differ diff --git a/assets/sfx/transition/whoosh.mp3 b/assets/sfx/transition/whoosh.mp3 new file mode 100644 index 0000000..a1f2910 Binary files /dev/null and b/assets/sfx/transition/whoosh.mp3 differ diff --git a/assets/sfx/ui/click-soft.mp3 b/assets/sfx/ui/click-soft.mp3 new file mode 100644 index 0000000..f59ea5c Binary files /dev/null and b/assets/sfx/ui/click-soft.mp3 differ diff --git a/assets/sfx/ui/click.mp3 b/assets/sfx/ui/click.mp3 new file mode 100644 index 0000000..c575046 Binary files /dev/null and b/assets/sfx/ui/click.mp3 differ diff --git a/assets/sfx/ui/focus.mp3 b/assets/sfx/ui/focus.mp3 new file mode 100644 index 0000000..e8a03ba Binary files /dev/null and b/assets/sfx/ui/focus.mp3 differ diff --git a/assets/sfx/ui/hover-subtle.mp3 b/assets/sfx/ui/hover-subtle.mp3 new file mode 100644 index 0000000..9ed6041 Binary files /dev/null and b/assets/sfx/ui/hover-subtle.mp3 differ diff --git a/assets/sfx/ui/tap-finger.mp3 b/assets/sfx/ui/tap-finger.mp3 new file mode 100644 index 0000000..bb688e7 Binary files /dev/null and b/assets/sfx/ui/tap-finger.mp3 differ diff --git a/assets/sfx/ui/toggle-on.mp3 b/assets/sfx/ui/toggle-on.mp3 new file mode 100644 index 0000000..7b2203e Binary files /dev/null and b/assets/sfx/ui/toggle-on.mp3 differ diff --git a/references/apple-gallery-showcase.md b/references/apple-gallery-showcase.md new file mode 100644 index 0000000..f9e92fa --- /dev/null +++ b/references/apple-gallery-showcase.md @@ -0,0 +1,338 @@ +# Apple Gallery Showcase · 画廊展示墙动画风格 + +> 灵感来源:Claude Design 官网 hero 视频 + 苹果产品页「作品墙」式陈列 +> 实战出处:huashu-design 发布 hero v5 +> 适用场景:**产品发布 hero 动画、skill 能力演示、作品集展示**——任何需要把「多件高质量产出」同时展陈并引导观众注意力的场景 + +--- + +## 触发判断:什么时候用这个风格 + +**适合**: +- 有10张以上真实产出要同屏展示(PPT、App、网页、信息图) +- 观众是专业受众(开发者、设计师、产品经理),对「质感」敏感 +- 希望传递的气质是「克制、展览式、高级、有空间感」 +- 需要焦点和全局同时存在(看细节但不失整体) + +**不适合**: +- 单产品聚焦(用 frontend-design 的产品 hero 模板) +- 情绪向/故事性强的动画(用时间轴叙事模板) +- 小屏幕 / 竖屏(倾斜视角在小画面上会糊) + +--- + +## 核心视觉 Token + +```css +:root { + /* 浅色画廊调板 */ + --bg: #F5F5F7; /* 主画布底 — 苹果官网灰 */ + --bg-warm: #FAF9F5; /* 温暖米白变体 */ + --ink: #1D1D1F; /* 主字色 */ + --ink-80: #3A3A3D; + --ink-60: #545458; + --muted: #86868B; /* 次级文字 */ + --dim: #C7C7CC; + --hairline: #E5E5EA; /* 卡片1px边框 */ + --accent: #D97757; /* 赤陶橙 — Claude brand */ + --accent-deep:#B85D3D; + + --serif-cn: "Noto Serif SC", "Songti SC", Georgia, serif; + --serif-en: "Source Serif 4", "Tiempos Headline", Georgia, serif; + --sans: "Inter", -apple-system, "PingFang SC", system-ui; + --mono: "JetBrains Mono", "SF Mono", ui-monospace; +} +``` + +**关键原则**: +1. **绝不用纯黑底**。黑底会让作品看起来像电影、不像「可以被采用的工作成果」 +2. **赤陶橙是唯一色相accent**,其他全部是灰阶 + 白 +3. **三字体栈**(serif英+serif中+sans+mono)营造「出版物」而非「互联网产品」的气质 + +--- + +## 核心布局模式 + +### 1. 悬浮卡片(整个风格的基本单元) + +```css +.gallery-card { + background: #FFFFFF; + border-radius: 14px; + padding: 6px; /* 内边距是「装裱纸」 */ + border: 1px solid var(--hairline); + box-shadow: + 0 20px 60px -20px rgba(29, 29, 31, 0.12), /* 主阴影,软且长 */ + 0 6px 18px -6px rgba(29, 29, 31, 0.06); /* 第二层近光,制造浮感 */ + aspect-ratio: 16 / 9; /* 统一 slide 比例 */ + overflow: hidden; +} +.gallery-card img { + width: 100%; height: 100%; + object-fit: cover; + border-radius: 9px; /* 比卡片圆角略小,视觉嵌套 */ +} +``` + +**反面教材**:不要贴边瓷砖(无padding无border无shadow)——那是信息图密度表达,不是展览。 + +### 2. 3D倾斜作品墙 + +```css +.gallery-viewport { + position: absolute; inset: 0; + overflow: hidden; + perspective: 2400px; /* 深一些的透视,倾斜不夸张 */ + perspective-origin: 50% 45%; +} +.gallery-canvas { + width: 4320px; /* 画布 = 2.25× viewport */ + height: 2520px; /* 留出pan空间 */ + transform-origin: center center; + transform: perspective(2400px) + rotateX(14deg) /* 向后倾 */ + rotateY(-10deg) /* 向左转 */ + rotateZ(-2deg); /* 轻微倾斜,去掉太规整 */ + display: grid; + grid-template-columns: repeat(8, 1fr); + gap: 40px; + padding: 60px; +} +``` + +**参数 sweet spot**: +- rotateX: 10-15deg(再多就像开酒会 VIP 背景板) +- rotateY: ±8-12deg(左右对称感) +- rotateZ: ±2-3deg(「这不是机器摆的」的人味) +- perspective: 2000-2800px(小于2000会鱼眼,大于3000接近正投影) + +### 3. 2×2 四角汇聚(选择场景) + +```css +.grid22 { + display: grid; + grid-template-columns: repeat(2, 800px); + gap: 56px 64px; + align-items: start; +} +``` + +每张卡片从对应角落(tl/tr/bl/br)向中心滑入 + fade in。对应的 `cornerEntry` 向量: + +```js +const cornerEntry = { + tl: { dx: -700, dy: -500 }, + tr: { dx: 700, dy: -500 }, + bl: { dx: -700, dy: 500 }, + br: { dx: 700, dy: 500 }, +}; +``` + +--- + +## 五种核心动画模式 + +### 模式 A · 四角汇聚(0.8-1.2s) + +4 个元素从视口四角滑入,同时缩放 0.85→1.0,对应 ease-out。适合「展示多方向选择」的开场。 + +```js +const inP = easeOut(clampLerp(t, start, end)); +card.style.transform = `translate3d(${(1-inP)*ce.dx}px, ${(1-inP)*ce.dy}px, 0) scale(${0.85 + 0.15*inP})`; +card.style.opacity = inP; +``` + +### 模式 B · 选中放大 + 其他滑出(0.8s) + +被选中的卡片放大 1.0→1.28,其他卡片 fade out + blur + 向四角漂回: + +```js +// 被选中 +card.style.transform = `translate3d(${cellDx*outP}px, ${cellDy*outP}px, 0) scale(${1 + 0.28*easeOut(zoomP)})`; +// 未选中 +card.style.opacity = 1 - outP; +card.style.filter = `blur(${outP * 1.5}px)`; +``` + +**关键**:未选中的要 blur,不是纯 fade。blur 模拟景深,视觉上把被选中的「推出来」。 + +### 模式 C · Ripple 涟漪展开(1.7s) + +从中心向外,按距离 delay,每张卡片依次淡入 + 从 1.25x 缩到 0.94x(「镜头拉远」): + +```js +const col = i % COLS, row = Math.floor(i / COLS); +const dc = col - (COLS-1)/2, dr = row - (ROWS-1)/2; +const dist = Math.sqrt(dc*dc + dr*dr); +const delay = (dist / maxDist) * 0.8; +const localT = Math.max(0, (t - rippleStart - delay) / 0.7); +card.style.opacity = easeOut(Math.min(1, localT)); + +// 同时整体 scale 1.25→0.94 +const galleryScale = 1.25 - 0.31 * easeOut(rippleProgress); +``` + +### 模式 D · Sinusoidal Pan(持续漂移) + +用正弦波 + 线性漂移组合,避免 marquee 那种「有起点有终点」的循环感: + +```js +const panX = Math.sin(panT * 0.12) * 220 - panT * 8; // 横向左漂 +const panY = Math.cos(panT * 0.09) * 120 - panT * 5; // 纵向上漂 +const clampedX = Math.max(-900, Math.min(900, panX)); // 防止露边 +``` + +**参数**: +- 正弦周期 `0.09-0.15 rad/s`(慢,约30-50秒一个摆动) +- 线性漂移 `5-8 px/s`(比观众眨眼慢) +- 振幅 `120-220 px`(大到能感觉,小到不会晕) + +### 模式 E · Focus Overlay(焦点切换) + +**关键设计**:focus overlay 是一个**平面元素**(不倾斜),浮在倾斜画布之上。被选中的 slide 从瓦片位置(约400×225)缩放到屏幕中央(960×540),背景画布不倾斜变化但**变暗到 45%**: + +```js +// Focus overlay (flat, centered) +focusOverlay.style.width = (startW + (endW - startW) * focusIntensity) + 'px'; +focusOverlay.style.height = (startH + (endH - startH) * focusIntensity) + 'px'; +focusOverlay.style.opacity = focusIntensity; + +// 背景卡片变暗,但依然可见(关键!不要100%遮罩) +card.style.opacity = entryOp * (1 - 0.55 * focusIntensity); // 1 → 0.45 +card.style.filter = `brightness(${1 - 0.3 * focusIntensity})`; +``` + +**清晰度铁律**: +- Focus overlay 的 `` 必须 `src` 直连原图,**不要复用 gallery 里的压缩缩略** +- 提前 preload 所有原图到 `new Image()[]` 数组 +- overlay 自身 `width/height` 按帧计算,浏览器每帧 resample 原图 + +--- + +## 时间轴架构(可复用骨架) + +```js +const T = { + DURATION: 25.0, + s1_in: [0.0, 0.8], s1_type: [1.0, 3.2], s1_out: [3.5, 4.0], + s2_in: [3.9, 5.1], s2_hold: [5.1, 7.0], s2_out: [7.0, 7.8], + s3_hold: [7.8, 8.3], s3_ripple: [8.3, 10.0], + panStart: 8.6, + focuses: [ + { start: 11.0, end: 12.7, idx: 2 }, + { start: 13.3, end: 15.0, idx: 3 }, + { start: 15.6, end: 17.3, idx: 10 }, + { start: 17.9, end: 19.6, idx: 16 }, + ], + s4_walloff: [21.1, 21.8], s4_in: [21.8, 22.7], s4_hold: [23.7, 25.0], +}; + +// 核心 easing +const easeOut = t => 1 - Math.pow(1 - t, 3); +const easeInOut = t => t < 0.5 ? 4*t*t*t : 1 - Math.pow(-2*t+2, 3)/2; +function lerp(time, start, end, fromV, toV, easing) { + if (time <= start) return fromV; + if (time >= end) return toV; + let p = (time - start) / (end - start); + if (easing) p = easing(p); + return fromV + (toV - fromV) * p; +} + +// 单一 render(t) 函数读时间戳、写所有元素 +function render(t) { /* ... */ } +requestAnimationFrame(function tick(now) { + const t = ((now - startMs) / 1000) % T.DURATION; + render(t); + requestAnimationFrame(tick); +}); +``` + +**架构精髓**:**所有状态由时间戳 t 推导**,没有状态机、没有 setTimeout。这样: +- 播放到任意时刻 `window.__setTime(12.3)` 立刻跳转(方便 playwright 逐帧截) +- 循环天然无缝(t mod DURATION) +- Debug 时能冻结任意一帧 + +--- + +## 质感细节(容易被忽略但致命) + +### 1. SVG noise texture + +浅色底最怕「太平」。叠加一层极弱的 fractalNoise: + +```html + +``` + +看上去没区别,去掉就知道有了。 + +### 2. 角落品牌标识 + +```html +
+
+
HUASHU · DESIGN
+
+``` + +```css +.corner-brand { + position: absolute; top: 48px; left: 72px; + font-family: var(--mono); + font-size: 12px; + letter-spacing: 0.22em; + text-transform: uppercase; + color: var(--muted); +} +``` + +只在作品墙 scene 显示,淡入淡出。像美术馆展签。 + +### 3. 品牌收束 wordmark + +```css +.brand-wordmark { + font-family: var(--sans); + font-size: 148px; + font-weight: 700; + letter-spacing: -0.045em; /* 负字距是关键,让字紧凑成标志 */ +} +.brand-wordmark .accent { + color: var(--accent); + font-weight: 500; /* accent字符反而细一点,视觉差 */ +} +``` + +`letter-spacing: -0.045em` 是苹果产品页大字的标准做法。 + +--- + +## 常见失败模式 + +| 症状 | 原因 | 解法 | +|---|---|---| +| 看起来像 PPT 模板 | 卡片没有 shadow / hairline | 加上两层 box-shadow + 1px border | +| 倾斜感廉价 | 只用了 rotateY 没加 rotateZ | 加 ±2-3deg rotateZ 打破工整 | +| Pan 感觉「卡顿」 | 用了 setTimeout 或 CSS keyframes 循环 | 用 rAF + sin/cos 连续函数 | +| Focus 时字看不清 | 复用了 gallery 瓦片的低分图 | 独立 overlay + 原图 src 直连 | +| 背景太空 | 纯色 `#F5F5F7` | 叠加 SVG fractalNoise 0.5 opacity | +| 字体太"互联网" | 只有 Inter | 加 Serif(中英各一)+ mono 三栈 | + +--- + +## 引用 + +- 完整实现样本:`/Users/alchain/Documents/写作/01-公众号写作/项目/2026.04-huashu-design发布/配图/hero-animation-v5.html` +- 原始灵感:claude.ai/design hero 视频 +- 参考审美:Apple 产品页、Dribbble shot 集合页 + +遇到「多件高质量产出要陈列」的动画需求,直接从此文件 copy 骨架,换内容 + 调 timing 即可。 diff --git a/references/audio-design-rules.md b/references/audio-design-rules.md new file mode 100644 index 0000000..42f31e8 --- /dev/null +++ b/references/audio-design-rules.md @@ -0,0 +1,260 @@ +# 音频设计规则 · huashu-design + +> 所有动画 demo 的音频应用配方。和 `sfx-library.md`(资产清单)配套使用。 +> 实战锤炼:huashu-design 发布 hero v1-v9 迭代 · Anthropic 三支官方片子的 Gemini 深度拆解 · 8000+ 次 A/B 对比 + +--- + +## 核心原则 · 音频双轨制(铁律) + +动画音频**必须分两层独立设计**,不能只做一层: + +| 层 | 作用 | 时间尺度 | 和视觉的关系 | 占据频段 | +|---|---|---|---|---| +| **SFX(节拍层)** | 标记每个视觉 beat | 0.2-2 秒短促 | **强同步**(帧级对齐) | **高频 800Hz+** | +| **BGM(氛围底)** | 情绪铺底、声场 | 连续 20-60 秒 | 弱同步(段落级) | **中低频 <4kHz** | + +**只做BGM的动画是残废的**——观众潜意识感知到「画在动但没声音响应」,廉价感的根源就在这里。 + +--- + +## 金标准 · 黄金配比 + +这几组数值是实测 Anthropic 三支官方片子 + 我们自己 v9 定版对比得出的**工程硬参数**,直接套用即可: + +### 音量 +- **BGM 音量**:`0.40-0.50`(相对满刻度 1.0) +- **SFX 音量**:`1.00` +- **响度差**:BGM 比 SFX peak **低 -6 到 -8 dB**(不是靠SFX绝对响度突出,靠响度差) +- **amix 参数**:`normalize=0`(绝不用 normalize=1,会把动态范围压平) + +### 频段隔离(P1 硬优化) +Anthropic 的秘诀不是「SFX 音量大」,是**频段分层**: + +```bash +[bgm_raw]lowpass=f=4000[bgm] # BGM 限制在 <4kHz 的中低频 +[sfx_raw]highpass=f=800[sfx] # SFX 推到 800Hz+ 的中高频 +[bgm][sfx]amix=inputs=2:duration=first:normalize=0[a] +``` + +为什么:人耳对 2-5kHz 区间最敏感(即「presence 频段」),SFX 如果都在这个区间,BGM 又全频段覆盖,**SFX 会被BGM的高频部分遮盖**。用 highpass 把 SFX 推高 + lowpass 把 BGM 压下,两者在频谱上各占一方,SFX 清晰度直接上一档。 + +### Fade +- BGM 入:`afade=in:st=0:d=0.3`(0.3s,避免硬切) +- BGM 出:`afade=out:st=N-1.5:d=1.5`(1.5s 长尾,收束感) +- SFX 自带 envelope,不需要额外 fade + +--- + +## SFX cue 设计规则 + +### 密度(每10秒多少个SFX) +实测 Anthropic 三支片子的 SFX 密度有三档: + +| 片子 | 每10s SFX 数 | 产品性格 | 场景 | +|---|---|---|---| +| Artifacts(ref-1) | **~9个/10s** | 功能密集、信息多 | 复杂工具演示 | +| Code Desktop(ref-2) | **0个** | 纯氛围、冥想感 | 开发工具专注状态 | +| Word(ref-3) | **~4个/10s** | 平衡、办公节奏 | 生产力工具 | + +**启发式**: +- 产品性格冷静/专注 → SFX 密度低(0-3个/10s),BGM 为主 +- 产品性格活泼/信息多 → SFX 密度高(6-9个/10s),SFX 驱动节奏 +- **不要填满每个视觉 beat**——留白比密集更高级。**删掉 30-50% 的 cue 会让剩下的更有戏剧性**。 + +### Cue 选择优先级 +每个视觉 beat 不都要配 SFX。按这个优先级选: + +**P0 必配**(省略会有违和感): +- 打字(终端/输入) +- 点击/选择(用户决策时刻) +- 焦点切换(视觉主角转移) +- Logo reveal(品牌收束) + +**P1 推荐配**: +- 元素入场/离场(modal / card) +- 完成/成功反馈 +- AI 生成开始/结束 +- 重大过渡(scene 切换) + +**P2 选配**(多了会乱): +- hover / focus-in +- 进度 tick +- 装饰性 ambient + +### 时间戳对齐精度 +- **同帧对齐**(0ms 误差):点击/焦点切换/Logo 落定 +- **前置 1-2 帧**(-33ms):快速 whoosh(给观众心理预期) +- **后置 1-2 帧**(+33ms):物体落地/impact(符合真实物理) + +--- + +## BGM 选择决策树 + +huashu-design skill 自带 6 首 BGM(`assets/bgm-*.mp3`): + +``` +动画性格是什么? +├─ 产品发布 / 技术演示 → bgm-tech.mp3(minimal synth + piano) +├─ 教程讲解 / 工具使用 → bgm-tutorial.mp3(warm, instructional) +├─ 教育学习 / 原理解释 → bgm-educational.mp3(curious, thoughtful) +├─ 营销广告 / 品牌宣传 → bgm-ad.mp3(upbeat, promotional) +└─ 同类风格需要变体 → bgm-*-alt.mp3(各自替代版) +``` + +### 无 BGM 的场景(值得考虑) +参考 Anthropic Code Desktop(ref-2):**0 SFX + 纯 Lo-fi BGM** 也能很高级。 + +**何时选无BGM**: +- 动画时长 <10s(BGM 建立不起来) +- 产品性格是「专注/冥想」 +- 场景本身有环境音/讲解声 +- SFX 密度很高时(避免听觉过载) + +--- + +## 场景配方(开箱即用) + +### 配方 A · 产品发布 hero(huashu-design v9 同款) +``` +时长:25 秒 +BGM:bgm-tech.mp3 · 45% · 频段 <4kHz +SFX 密度:~6个/10s + +cue: + 终端打字 → type × 4(间隔0.6s) + 回车 → enter + 卡片汇聚 → card × 4(错峰 0.2s) + 选中 → click + Ripple → whoosh + 4次焦点 → focus × 4 + Logo → thud(1.5s) + +音量:BGM 0.45 / SFX 1.0 · amix normalize=0 +``` + +### 配方 B · 工具功能演示(参考 Anthropic Code Desktop) +``` +时长:30-45 秒 +BGM:bgm-tutorial.mp3 · 50% +SFX 密度:0-2个/10s(极少) + +策略:让 BGM + 讲解 voiceover 驱动,SFX 只在**决定性时刻**(文件保存/命令执行完成) +``` + +### 配方 C · AI 生成演示 +``` +时长:15-20 秒 +BGM:bgm-tech.mp3 或无 BGM +SFX 密度:~8个/10s(高密度) + +cue: + 用户输入 → type + enter + AI 开始处理 → magic/ai-process(1.2s 循环) + 生成完成 → feedback/complete-done + 结果呈现 → magic/sparkle + +亮点:ai-process 可以循环 2-3 次贯穿整个生成过程 +``` + +### 配方 D · 纯氛围长镜头(参考 Artifacts) +``` +时长:10-15 秒 +BGM:无 +SFX:单独使用 3-5 个精心设计的 cue + +策略:每个 SFX 都是主角,没有BGM「糊在一起」的问题。 +适合:单产品慢镜头、特写展示 +``` + +--- + +## ffmpeg 合成模板 + +### 模板 1 · 单 SFX 叠加到视频 +```bash +ffmpeg -y -i video.mp4 -itsoffset 2.5 -i sfx.mp3 \ + -filter_complex "[0:a][1:a]amix=inputs=2:normalize=0[a]" \ + -map 0:v -map "[a]" output.mp4 +``` + +### 模板 2 · 多 SFX 时间轴合成(按cue时间对齐) +```bash +ffmpeg -y \ + -i sfx-type.mp3 -i sfx-enter.mp3 -i sfx-click.mp3 -i sfx-thud.mp3 \ + -filter_complex "\ +[0:a]adelay=1100|1100[a0];\ +[1:a]adelay=3200|3200[a1];\ +[2:a]adelay=7000|7000[a2];\ +[3:a]adelay=21800|21800[a3];\ +[a0][a1][a2][a3]amix=inputs=4:duration=longest:normalize=0[mixed]" \ + -map "[mixed]" -t 25 sfx-track.mp3 +``` +**关键参数**: +- `adelay=N|N`:前面是左声道延迟(ms),后面是右声道,写两遍保证立体声对齐 +- `normalize=0`:保留动态范围,关键! +- `-t 25`:截断到指定时长 + +### 模板 3 · 视频 + SFX track + BGM(带频段隔离) +```bash +ffmpeg -y -i video.mp4 -i sfx-track.mp3 -i bgm.mp3 \ + -filter_complex "\ +[2:a]atrim=0:25,afade=in:st=0:d=0.3,afade=out:st=23.5:d=1.5,\ + lowpass=f=4000,volume=0.45[bgm];\ +[1:a]highpass=f=800,volume=1.0[sfx];\ +[bgm][sfx]amix=inputs=2:duration=first:normalize=0[a]" \ + -map 0:v -map "[a]" -c:v copy -c:a aac -b:a 192k final.mp4 +``` + +--- + +## 失败模式速查 + +| 症状 | 根因 | 修复 | +|---|---|---| +| SFX 听不见 | BGM 高频部分遮盖 | 加 `lowpass=f=4000` 给BGM + `highpass=f=800` 给SFX | +| 音效过响刺耳 | SFX 绝对音量太大 | SFX 音量降到 0.7,同时降低 BGM 到 0.3,保持差值 | +| BGM 和 SFX 节奏冲突 | BGM 选错了(用了有强beat的music) | 换成 ambient / minimal synth 的 BGM | +| 动画结束 BGM 突然断 | 没做 fade out | `afade=out:st=N-1.5:d=1.5` | +| SFX 重叠成糊 | cue 太密 + 每个 SFX 时长太长 | SFX 时长控到 0.5s 以内,cue 间隔 ≥ 0.2s | +| 公众号 mp4 没声音 | 公众号有时会 mute auto-play | 不用担心,用户点开会有声音;gif 本来就没声音 | + +--- + +## 和视觉的联动(高级) + +### SFX 音色要和视觉风格匹配 +- 暖米/纸张感视觉 → SFX 用**木质/柔和**音色(Morse, paper snap, soft click) +- 冷黑科技视觉 → SFX 用**金属/数字**音色(beep, pulse, glitch) +- 手绘/童趣视觉 → SFX 用**卡通/夸张**音色(boing, pop, zap) + +我们当前 `apple-gallery-showcase.md` 的暖米底色 → 搭配 `keyboard/type.mp3`(mechanical)+ `container/card-snap.mp3`(soft)+ `impact/logo-reveal-v2.mp3`(cinematic bass) + +### SFX 可以引导视觉节奏 +高级技巧:**先设计 SFX 时间轴,然后调整视觉动画去对齐 SFX**(不是反过来)。 +因为 SFX 每个 cue 都是一个「钟表 tick」,视觉动画适配 SFX 节奏会非常稳——反之 SFX 去追视觉,常常 ±1 帧对不上就有违和感。 + +--- + +## 质量检查清单(发布前自检) + +- [ ] 响度差:SFX peak - BGM peak = -6 到 -8 dB? +- [ ] 频段:BGM lowpass 4kHz + SFX highpass 800Hz? +- [ ] amix normalize=0(保留动态范围)? +- [ ] BGM fade-in 0.3s + fade-out 1.5s? +- [ ] SFX 数量是否合适(按场景性格选密度)? +- [ ] 每个 SFX 和视觉 beat 同帧对齐(±1 帧内)? +- [ ] Logo reveal 音效时长够(建议 1.5s)? +- [ ] 关闭 BGM 听一遍:SFX 单独是否足够有节奏感? +- [ ] 关闭 SFX 听一遍:BGM 单独是否有情绪起伏? + +两层任何一层单独听都应该自洽。如果只有两层叠加才好听,说明没做好。 + +--- + +## 参考 + +- SFX 资产清单:`sfx-library.md` +- 视觉风格参考:`apple-gallery-showcase.md` +- Anthropic 三支片子深度音频分析:`/Users/alchain/Documents/写作/01-公众号写作/项目/2026.04-huashu-design发布/参考动画/AUDIO-BEST-PRACTICES.md` +- huashu-design v9 实战案例:`/Users/alchain/Documents/写作/01-公众号写作/项目/2026.04-huashu-design发布/配图/hero-animation-v9-final.mp4` diff --git a/references/sfx-library.md b/references/sfx-library.md new file mode 100644 index 0000000..50b2369 --- /dev/null +++ b/references/sfx-library.md @@ -0,0 +1,226 @@ +# SFX Library · huashu-design + +> 全部由 ElevenLabs Sound Generation API 生成,苹果发布会级音质。 +> 产品级 SFX 资产库,覆盖花叔动画/演示/产品 Demo 全场景。 + +**资产位置**:`assets/sfx//.mp3` +**总数**:37 个 SFX(30 批量生成 + 7 个 v7b 保留) +**生成模型**:ElevenLabs Sound Generation API(prompt_influence 0.4) +**音质**:44.1kHz MP3,苹果发布会级清晰度,无额外混响 + +--- + +## 目录结构 + +``` +assets/sfx/ +├── keyboard/ type, type-fast, delete-key, space-tap, enter +├── ui/ click, click-soft, focus, hover-subtle, tap-finger, toggle-on +├── transition/ whoosh, whoosh-fast, swipe-horizontal, slide-in, dissolve +├── container/ card-snap, card-flip, stack-collapse, modal-open +├── feedback/ success-chime, error-tone, notification-pop, achievement +├── progress/ loading-tick, complete-done, generate-start +├── impact/ logo-reveal, logo-reveal-v2, brand-stamp, drop-thud +├── magic/ sparkle, ai-process, transform +└── terminal/ command-execute, output-appear, cursor-blink +``` + +--- + +## 快速索引 + +### ⌨️ Keyboard(键盘输入) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/keyboard/type.mp3` | 0.5s | 单键敲击(mechanical keyboard single key) | mechanical keyboard single key press | +| `sfx/keyboard/type-fast.mp3` | 1.5s | 连续快速打字(演示输入提示词) | fast continuous typing rhythm, apple magic keyboard | +| `sfx/keyboard/delete-key.mp3` | 0.5s | backspace 回删 | single backspace key, low pitched thud | +| `sfx/keyboard/space-tap.mp3` | 0.5s | 空格键轻击 | soft spacebar tap, wide flat | +| `sfx/keyboard/enter.mp3` | 0.5s | 回车确认(v7b 保留) | enter key press, crisp tactile | + +### 🎯 UI(界面交互) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/ui/click.mp3` | 0.5s | 标准 UI 点击(v7b 保留) | crisp modern interface click | +| `sfx/ui/click-soft.mp3` | 0.5s | 柔和 UI click(次要按钮/链接) | soft gentle button click, mid pitched | +| `sfx/ui/focus.mp3` | 0.5s | 元素聚焦/选中(v7b 保留) | subtle focus tone, element highlight | +| `sfx/ui/hover-subtle.mp3` | 0.5s | 悬停提示(微秒级反馈) | barely audible tick, air whisper | +| `sfx/ui/tap-finger.mp3` | 0.5s | 移动端 tap(iOS 界面) | finger tap on touchscreen, muted thud | +| `sfx/ui/toggle-on.mp3` | 0.5s | 开关打开 | ios toggle switch flip, satisfying click | + +### 🌊 Transition(过渡) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/transition/whoosh.mp3` | 0.5s | 标准 whoosh(v7b 保留) | air whoosh transition | +| `sfx/transition/whoosh-fast.mp3` | 0.6s | 快速 whoosh(标题闪入、标签切换) | quick fast air whoosh, cinematic | +| `sfx/transition/swipe-horizontal.mp3` | 0.7s | 横向滑动(轮播、tab 切换) | smooth left-to-right air movement | +| `sfx/transition/slide-in.mp3` | 0.6s | 元素滑入(side panel、抽屉) | smooth soft whoosh with arrival | +| `sfx/transition/dissolve.mp3` | 0.8s | 柔化融化(图片淡出淡入) | soft dissolve, airy shimmer | + +### 🃏 Container(卡片/容器) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/container/card-snap.mp3` | 0.5s | 卡片吸附/定位(v7b 保留) | card snap into place | +| `sfx/container/card-flip.mp3` | 0.7s | 卡片翻转(前后面切换) | playing card flip, crisp snap | +| `sfx/container/stack-collapse.mp3` | 0.8s | 堆叠合拢(列表聚合) | cards stacking, paper taps collapsing | +| `sfx/container/modal-open.mp3` | 0.6s | 模态框打开 | modal popping open, whoosh + thud | + +### 🔔 Feedback(通知/反馈) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/feedback/success-chime.mp3` | 1.0s | 成功提示(支付成功、任务完成) | two ascending bell tones, ios-style | +| `sfx/feedback/error-tone.mp3` | 0.7s | 错误提示(警告、失败) | descending two-note warning, soft | +| `sfx/feedback/notification-pop.mp3` | 0.6s | 消息弹出(toast、通知) | notification bloop, ios message alert | +| `sfx/feedback/achievement.mp3` | 1.5s | 成就达成(里程碑、徽章) | triumphant rising arpeggio, game-style | + +### ⏳ Progress(进度/状态) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/progress/loading-tick.mp3` | 0.5s | 加载计时(进度条节拍) | soft short pulse, minimal ambient | +| `sfx/progress/complete-done.mp3` | 0.8s | 完成确认(step 完成) | two ascending satisfying tones | +| `sfx/progress/generate-start.mp3` | 0.8s | AI 开始生成 | soft rising shimmer, magical whoosh | + +### 💥 Impact(品牌/冲击) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/impact/logo-reveal.mp3` | 0.7s | Logo impact(v7b 保留) | logo reveal thud | +| `sfx/impact/logo-reveal-v2.mp3` | 1.5s | 更长的 Logo impact(电影感) | cinematic bass hit with shimmer tail | +| `sfx/impact/brand-stamp.mp3` | 1.0s | 印章重击(认证、盖章) | rubber stamp thud, paper contact | +| `sfx/impact/drop-thud.mp3` | 0.7s | 物件落地(插入、放置) | heavy thud, wood surface contact | + +### ✨ Magic(AI 变换) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/magic/sparkle.mp3` | 0.8s | 魔法闪光(AI 高亮、惊喜) | bright twinkling stars, fairy dust | +| `sfx/magic/ai-process.mp3` | 1.2s | AI 处理音(thinking 状态) | modulating digital hum with shimmer | +| `sfx/magic/transform.mp3` | 1.0s | 变换过渡(morph 效果) | rising shimmer whoosh with sparkle tail | + +### 💻 Terminal(命令行) + +| 文件 | 时长 | 用途 | Prompt 要点 | +|---|---|---|---| +| `sfx/terminal/command-execute.mp3` | 0.5s | 命令执行 | crisp digital beep with tick, hacker ui | +| `sfx/terminal/output-appear.mp3` | 0.6s | 输出出现 | rapid digital ticks, retro printout | +| `sfx/terminal/cursor-blink.mp3` | 0.5s | 光标闪烁 | subtle soft digital pulse, rhythmic | + +--- + +## 按场景推荐搭配 + +### 💻 Terminal 交互演示 +``` +type (0.5s) → enter (0.5s) → command-execute (0.5s) → output-appear (0.6s) +``` +循环元素:`cursor-blink` 作为 idle 时的环境音。 + +### 🃏 卡片选择流程 +``` +hover-subtle (0.5s, UI悬停) → click-soft (0.5s, 点击) → card-snap (0.5s, 定位) +``` +或进阶版:`card-flip` 做前后面切换。 + +### 🤖 AI 生成全流程 +``` +generate-start (0.8s, 启动) → ai-process (1.2s, 处理) → sparkle (0.8s, 闪现) → complete-done (0.8s, 完成) +``` +错误时用 `error-tone` 替代 `complete-done`。 + +### 🎬 Logo Reveal(品牌时刻) +``` +whoosh-fast (0.6s, 铺垫) → logo-reveal-v2 (1.5s, 落点) → sparkle (0.8s, 尾韵) +``` +简版:`whoosh → logo-reveal`(直接 v7b 两件套)。 + +### 📱 UI 交互演示(移动端) +``` +tap-finger (0.5s, 点击) → slide-in (0.6s, 面板滑入) → toggle-on (0.5s, 开关) +``` +完成后:`success-chime` 或 `notification-pop`。 + +### 📊 数据可视化/仪表盘 +``` +loading-tick (0.5s, 节拍) × N → complete-done (0.8s, 数据到位) → achievement (1.5s, 惊艳落点) +``` + +### 🎯 表单提交流程 +``` +click-soft (0.5s) → loading-tick ×2 (1.0s) → success-chime (1.0s) +``` +失败分支:`error-tone (0.7s)`。 + +### 🪄 Magic Transform 场景 +``` +whoosh-fast (0.6s) → transform (1.0s) → sparkle (0.8s) +``` +适合:元素变形、效果前后对比、"AI 重写"等演示。 + +--- + +## 使用规范 + +### 音量建议(来自 apple-gallery-showcase.md 音频双轨制) +- **SFX 主轨**:`1.0`(不做衰减) +- **BGM 背景轨**:`0.4 ~ 0.5`(SFX 明显穿透) +- **多 SFX 叠加**:用 `amix=inputs=N:duration=longest:normalize=0` 保留动态范围 + +### ffmpeg 拼接模板 +```bash +# 单 SFX 对齐时间点: +ffmpeg -i video.mp4 -itsoffset 2.5 -i sfx/ui/click.mp3 \ + -filter_complex "[0:a][1:a]amix=inputs=2:duration=longest:normalize=0[a]" \ + -map 0:v -map "[a]" output.mp4 + +# 多 SFX + BGM: +ffmpeg -i video.mp4 \ + -itsoffset 1.0 -i sfx/transition/whoosh-fast.mp3 \ + -itsoffset 1.6 -i sfx/impact/logo-reveal-v2.mp3 \ + -i bgm.mp3 \ + -filter_complex "[3:a]volume=0.4[bgm];[0:a][1:a][2:a][bgm]amix=inputs=4:normalize=0[a]" \ + -map 0:v -map "[a]" output.mp4 +``` + +### 选型决策树 +1. **有 tactile 动作**(打字/点击/滑动)→ `keyboard/` or `ui/` +2. **元素进场/出场** → `transition/` +3. **容器层操作**(卡片/模态) → `container/` +4. **状态反馈**(成功/失败/通知) → `feedback/` +5. **进度/时间流逝** → `progress/` +6. **品牌落点/重要时刻** → `impact/` +7. **AI 魔法/变换** → `magic/` +8. **命令行/代码演示** → `terminal/` + +### 避免叠音堆积 +- 同一个时间点 `max 2 个 SFX` 并发 +- BGM 降到 0.3 以下时可以放 3 个 +- 品牌 impact 时清空其他 SFX(留空 0.2s 再落点) + +--- + +## Prompt 撰写原则(供复用) + +参考风格:`apple keynote, tight, minimal, no reverb unless ambient, crisp, elegant` + +**好 prompt 的三要素**: +1. **声音物理描述**:什么物体、什么动作("mechanical keyboard single key press") +2. **质感/风格限定**:apple-style / ios-style / cinematic / retro +3. **反例排除**:no reverb / clean studio / minimal + +❌ "click sound" +✅ "crisp ui button click, clean modern interface sound, apple-style, high pitched" + +❌ "magic" +✅ "bright twinkling stars sound, high pitched glittery chime, fairy dust" + +--- + +## 详见 +- 音频双轨制与 ffmpeg 拼接:`apple-gallery-showcase.md` +- 原始生成脚本:`/tmp/gen_sfx_batch.sh`(一次性批量生成器)