关于 parallax-landing-page
将短视频转换为单屏落地页的技能,页面通过滚动逐帧播放视频,并呈现五段交叉淡入淡出的文字场景。它指导抽取视频帧、编写页面,以及创建独立页面或集成到现有展示站点。
主要功能
- 01使用内置脚本抽取视频帧
- 02通过滚动、触控或键盘逐帧播放
- 03创建五段定时文字场景和最终 CTA
- 04创建独立页面或扩展展示站点
- 05使用提供的页面模板和共享资源
适用场景
- 01将简短产品视频制作成落地页
- 02为个人或野生动物视频制作电影感页面
- 03向 parasites 展示站点添加新页面
- 04基于 MP4 构建滚动逐帧体验
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ hoodini/ ai-agents-skills --skill parallax-landing-page安装后在 Claude Code 中输入/parallax-landing-page确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
assets/hub-template.htmllanding-page-template.htmlparallax.jsstyle.cssreferences/copy-guide.mdshowcase-integration.mdscripts/extract_frames.py详细介绍
视差着陆页
将一段短视频变成一屏式的电影感着陆页:用户滚动时,视频会逐帧播放,同时五个戏剧化文字场景交替淡入淡出。文档本身不会真正滚动——JS 会拦截滚轮、触控和键盘输入,并将其转换为虚拟的帧进度。
此技能总结了随附参考示例 ../../examples/parasites/ 中验证过的模式(github / lion / hope 着陆页——三个使用此技能构建的可运行页面)。如果此处有任何含糊之处,请以该目录为准。
此技能在 YUV.AI 金字塔中的位置
parallax-landing-page 位于 YUV.AI 技能金字塔的中间层,与 yuv-design-system、yuv-decks、yuv-viral-video 和 video-to-landing-page 并列。只要需要将 5–15 秒的视频片段制作成单个主视觉滚动擦动式着陆页,顶层编排器 yuv-pilot 就会将任务路由到此处。
此技能自带视觉语言(Anton + Caveat + Inter、金色/琥珀色/强调色/奶油色点缀配色)——它不会调用 yuv-design-system。这两个系统可以共存:yuv-design-system 负责跨网页/应用/演示文稿界面的品牌配色,parallax-landing-page 则专门负责电影感滚动擦动美学。对于 YUV.AI 视差着陆页,可选择性地在页脚区域添加凤凰水印和规范的 Linktree URL,以贯穿品牌形象——水印文件见 yuv-design-system/assets/。不要将 Anton/Caveat 字体组合替换为设计系统的 Neon 配色,否则会失去标志性外观。
构建内容
每个着陆页都是一个锁定的单屏视口,包含:
- 填满屏幕的画布,逐帧绘制视频画面(按容器尺寸缩放以覆盖画布,DPR ≤ 2)
- 5 个绝对定位的文字场景(引导语 + 全大写 Anton 标题 + Caveat 手写风格文案),每个场景都有自己的滚动进度区间
- 固定导航栏,包含
PARALLAX // showcase标志和指向同系列其他着陆页的链接 - 加载器,在允许用户交互前预加载所有帧
- 暗角 + 胶片颗粒叠加层
- 底部滚动提示,用户开始滚动后淡出
- 右下角帧计数器(例如
073 / 145) - 最后一个场景本身就是 CTA 区域——下方不再有独立的
.end区域
q:v 为 2 时,总体积约为每帧 120–220 KB × 帧数。6 秒、24fps 的视频片段 = 145 帧 ≈ 25 MB。10 秒的视频片段 = 241 帧 ≈ 53 MB。
保存位置
默认位置: ~/Documents/yuv-projects/landings/<slug>/——独立着陆页始终保存在此处,方便之后查找。仅当用户明确指定其他位置,或选择模式 B(集成到现有的 examples/parasites/ 展示项目)时,才覆盖此默认位置。
mkdir -p ~/Documents/yuv-projects/landings
cd ~/Documents/yuv-projects/landings
# The skill creates <slug>/ here as it extracts frames and builds the HTML.
最终路径(模式 A——独立项目):~/Documents/yuv-projects/landings/<slug>/。
最终路径(模式 B——集成项目):用户选择的现有展示项目目录。
每次构建结束时,都要告知用户最终路径。
工作流
共有四个阶段。不要跳过任何阶段——每个阶段都是下一阶段的基础。
阶段 1 — 探索
与用户确认:
- 视频路径 — 源 MP4 文件所在位置。
- Slug — 简短的文件夹/文件名(例如
hope、marcus、desk)。使用一个单词,全小写,不含空格。它将同时作为帧文件夹名(<slug>/)和 HTML 文件名(<slug>.html)。 - 主题 / 话题 — 这个落地页的主题是什么?产品发布?个人时刻?野生动物邂逅?你需要了解这些,才能撰写文案。
- 项目模式 — 独立(全新文件夹),或整合到现有的
examples/parasites/展示项目中(位于此仓库顶层)。如果用户说“把它加到展示项目中”,指的就是下方的模式 B。 - 强调色 — 用于手写文案/CTA 高亮:
gold(#f5b042)、amber(#ff8a3d)、accent(粉色 #ff4d6d)、cream(#f5e9d4),或其他颜色(将其添加到 style.css 的:root中,并编写新的.script.<name>规则)。
如果用户没有指定其中某些信息,请提出默认选项并继续操作——不要因为这些他们可以在看到结果后再回答的问题而停滞不前。
阶段 2 — 提取帧
运行随附的提取脚本。脚本使用 ffprobe 检查视频,并以原生分辨率通过 -q:v 2(接近无损的 JPEG)提取每一帧,命名为 frame-001.jpg 至 frame-NNN.jpg(3 位数字,前面补零)。
python <skill>/scripts/extract_frames.py <video_path> <output_folder>
示例:
python C:/Users/User/.claude/skills/parallax-landing-page/scripts/extract_frames.py \
C:/Users/User/Documents/parasites/hope/hope.mp4 \
C:/Users/User/Documents/parasites/hope
脚本会向 stdout 输出一个 JSON 元数据块。请保存好它——HTML 需要用到 frame_count 和 suggested_scroll_budget。
为什么使用 -q:v 2:ezgif 等工具会大幅重新压缩(每帧约 55 KB)。原生 ffmpeg 使用 q:v 2,在相同尺寸下每帧约为 120–220 KB,画面明显更清晰。不要缩小尺寸;绝不要放大(这会增加文件体积,却不会增添细节)。
为什么采用此滚动预算公式(每帧约 26 px):这样无论片段时长如何,“每推进一帧所需滚动的像素数”都能保持一致。145 帧 → 约 4200,241 帧 → 约 6300,90 帧 → 约 2500(下限)。脚本会为你计算,并将数值限制在 [2500, 8000] 范围内。
阶段 3 — 编写页面
阅读 <skill>/assets/landing-page-template.html 中的模板。这是一个完整可用的文件,包含 {{PLACEHOLDER}} 标记,创意文案旁还有 `` 注释。将所有内容替换后,写入新文件 <target>/<slug>.html。
替换清单(必须替换每个占位符):
| 占位符 | 填入内容 | 示例 |
|---|---|---|
{{PAGE_TITLE}} | HTML <title> | Hope — The Fastest Heart in the Negev |
{{PAGE_DESCRIPTION}} | 一句话的 meta description | 与 Hope 一同度过片刻,认识这只来自 Midbarium 的猎豹。 |
{{SLUG}} | 文件夹名(不含路径、不含斜杠) | hope |
{{FRAME_COUNT}} | 帧数整数 | 241 |
{{FRAME_COUNTER_TEXT}} | 与帧数位数匹配的 001 / NNN | 001 / 241 |
{{SCROLL_BUDGET}} | 提取器 JSON 中的整数 | 6300 |
{{PREVIEW_FRAME_MID}} | 补零后的中间帧编号 | 121 |
{{PREVIEW_FRAME_END}} | 补零后的最后一帧编号 | 241 |
{{LOADER_TITLE}} | 一个大写单词 | HOPE |
{{LOADER_SCRIPT}} | 以 … 结尾的手写风格文案 | 正在召唤奔跑者… |
{{NAV_LINKS_HTML}} | 用于导航栏的完整 <a> 标签块 | 见下文 |
{{SCENE_N_*}} | 5 个场景各自的引导语、标题、手写风格文案 | 见文案指南 |
{{SCROLL_HINT_TEXT}} | 2–4 个单词的全大写提示语 | SCROLL TO RUN |
{{CTA_BUTTONS_HTML}} | 2–4 个 <a class="cta"> 标签 | 见下文 |
{{ACCENT_CLASS}} | .script.X 和 .cta.X 的强调色后缀 | amber |
阅读 references/copy-guide.md,了解电影感文案的写作模式(引导语措辞、标题长度、手写风格文案的语气)。文案是这项技能发挥价值的关键——即使动画再精美,泛泛的文案也会毁掉整体效果。
阶段 4 — 接入资源
如果目标文件夹中已有 style.css 和 parallax.js(展集成),则无需操作——它们是共享的。否则,将这两个文件从 <skill>/assets/ 复制到目标文件夹:
cp <skill>/assets/style.css <target>/style.css
cp <skill>/assets/parallax.js <target>/parallax.js
如果要集成到现有展集中,还需执行 references/showcase-integration.md 中的步骤——在 index.html 中添加卡片,为每个现有落地页的导航栏添加链接,并在前一个落地页的最终场景中添加链式 CTA。
告知用户如何查看:
在父文件夹中运行
python -m http.server 8000,通过此方式打开<target>/<slug>.html(不要使用file://——Chromium 可能会因本地图片来源污染画布)。
文件约定
<target>/
├── <slug>/ # frame folder
│ ├── <slug>.mp4 # the source (preserved)
│ ├── frame-001.jpg
│ ├── frame-002.jpg
│ └── … frame-NNN.jpg
├── <slug>.html # the landing page
├── style.css # shared (copy if standalone)
├── parallax.js # shared (copy if standalone)
└── index.html # the hub (only if standalone or integration)
帧文件夹名称和 HTML 文件名必须使用相同的 slug——页面的 new ParallaxPage({folder: '<slug>', ...}) 调用中的 folder 选项就是字面文件夹路径。
ParallaxPage API(已在 parallax.js 中定义,不要重新定义)
new ParallaxPage({
folder: '<slug>', // folder containing frame-001.jpg, etc.
frameCount: 145, // integer
prefix: 'frame-', // always 'frame-' for this skill
scrollBudget: 4200, // pixels of accumulated input for full pass
// optional: padWidth (default 3), ext (default 'jpg')
})
该类会自动为 body 添加 scrub-page(通过 CSS 锁定滚动),预加载所有帧,运行由 RAF 驱动的 lerp(系数为 0.22),向由滚动位置推导出的目标帧推进,并对 data-start/data-end 范围包含当前进度的场景进行交叉淡入淡出。
硬性约束(不可妥协)
这些约束已融入参考实现,违反后会破坏体验:
- 5 个场景,固定进度区间:
0.00–0.20、0.22–0.40、0.42–0.60、0.62–0.80、0.82–1.00。场景之间故意留出 0.02 的间隔——这是每个节拍之间“只有图像、没有文字”的瞬间。首屏(场景 1)和最终场景(场景 5)分别使用data-fade="0.30"和data-fade="0.18",让它们在边缘停留更久;中间场景使用默认值 0.25。 - scrub 下方不得有
.end区块。最终场景包含 CTA。整个页面是一个锁定的视口。 - Anton + Caveat + Inter——所有粗体文字均使用大写 Anton,手写风格点缀(gold/amber/cream)使用 Caveat,正文引导文字使用 Inter。不得替换,也不得添加第四种字体。
- 使用米白色
#f5f1ea,绝不使用#fff——CSS 中已定义为var(--text)。 - 帧文件名采用
frame-NNN.jpg,根据总帧数补零至相同位数(由于片段少于 1000 帧,标准为 3 位;JS 会根据总数自动计算计数器位数)。 - slug 同时作为文件夹名称和 HTML 文件名的基本名称——
hope/、hope.html。不得例外;集成步骤依赖此约定。
遇到问题时的参考资料
- 本仓库中随附的参考展集:
examples/parasites/— github.html、lion.html、hope.html、style.css、parallax.js、index.html。如果你的输出与这些示例明显不同,说明实现偏离了;请重新阅读。 references/copy-guide.md——如何撰写 5 个场景,让它们真正具有电影感。references/showcase-integration.md——添加到现有中心页时需要进行的具体修改。assets/landing-page-template.html——包含占位符的标准结构。assets/hub-template.html——仅在创建全新展集时使用(从零开始添加 3 张卡片)。
两个实际调用示例
**独立页面:**用户有一个视频片段 desk.mp4,并想制作一个落地页。
- 询问 slug 和主题。对
desk.mp4运行提取器 →./desk/frame-NNN.jpg。 - 将
style.css和parallax.js复制到项目根目录。 - 根据模板编写
desk.html。导航栏中只有一个链接:页面自身。 - 完成。告知用户使用
python -m http.server启动服务。
**添加到展集:**用户将 hope.mp4 添加到现有的 parasites 文件夹。
- slug =
hope。提取帧 →hope/frame-NNN.jpg。(复用现有的 style.css 和 parallax.js。) - 根据模板编写
hope.html。 - 执行展集集成:在
index.html中添加第三张卡片,在github.html和lion.html的导航栏中追加Hope链接,并在前一个落地页的最终场景中添加Next: Hope →CTA。 - 如果引入新的点缀色,则将其添加到
:root,并在style.css中添加.script.X和.cta.X规则。