mcpField
S
scroll-world

scroll-world

github.com/cth9191设计与 UI56469 次安装16 周前更新
代码仓库

关于 scroll-world

scroll-world 是一项用于生成滚动驱动镜头连续飞行的落地页技能,借助 Higgsfield 制作场景图与视频片段,并拼接成无明显切口的旅程。它提供帧一致性检查和可嵌入不同网页环境的原生 JavaScript 播放引擎。

主要功能

  1. 01生成连贯的场景图与镜头片段
  2. 02拼接场景间连接视频
  3. 03自动检查片段接缝
  4. 04提供可移植的滚动播放引擎
  5. 05支持移动端素材与降级处理

适用场景

  1. 01制作连续镜头式产品落地页
  2. 02展示品牌或产品的场景旅程
  3. 03为网页配置移动端视频素材
  4. 04在不同网页环境嵌入滚动动画

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cth9191/scroll-world --skill scroll-world

安装后在 Claude Code 中输入/scroll-world确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
gotchas.md
index-template.html
knockout.py
pipeline.md
prompts.md
scrub-engine.js

详细介绍

scroll-world

生成一个落地页,其中滚动会驱动摄像机:摄像机从场景外部俯冲进入内部,然后飞出并进入下一个场景,整个过程连贯不间断,没有可见的剪切。视觉内容由 AI 生成(Higgsfield);页面只需根据滚动位置定位到预渲染视频的相应时间。这与 Apple 产品页面中的滚动浏览效果采用的是同一种技术——摄像机确实在移动,滚动只负责驱动时间轴。

**生成内容:**N 张场景静帧(经锚点确认)→ N 段“俯冲进入”摄像机视频片段 → N-1 段将连续场景无缝衔接的“连接片段”→ 编码后的视频片段和提取的海报图 → 自动 SSIM 接缝检查 → 一个可移植的定位引擎,将整条片段链作为一次飞行播放。默认先用低成本预览档渲染链中的片段;只有用户批准草稿后,才会消耗完整模型额度。

**成败的关键规则:**接缝必须做到帧完全一致。生成任何连接片段之前,请先阅读无缝衔接。这是最常见的失败原因,一旦处理错误,场景之间就会出现明显的“跳变”。

不要假设项目使用某个前端框架。references/scrub-engine.js 中的定位引擎是独立的原生 JS(它会在你提供的容器中自行构建 DOM 并注入 CSS),因此可用于纯 HTML、Next.js、Vue、由 Python 提供服务的页面等任何环境。这项技能的价值在于 Higgsfield 工作流、提示词和接缝处理方法,而非框架。


第 0 步 — 初始化

  1. **Higgsfield CLI。**如果 $PATH 中没有 higgsfield,请按照 higgsfield-generate 技能进行安装。如果 higgsfield workspace list 遇到身份验证失败,请让用户运行 higgsfield auth login(交互式 OAuth,你无法代为运行);必要时再运行 higgsfield workspace set <id>。确认额度充足:一次运行需要 N 次图像生成和 N 次视频生成(架构 A),或 (2N-1) 次视频生成(架构 B),另外还要预留重新生成的额度——第 1 步的预算档位决定 N。
  2. 确保 $PATH 中有 ffmpeg / ffprobe(用于提取帧和编码)。
  3. 用于抠除背景的图像工具,如果你想让场景悬浮显示:PIL(python3 -c "import PIL"),或 cwebp/sips。可选,见第 3 步。
  4. 注意事项:macOS 自带的是 bash 3.2(不支持 declare -A);脚本中不要使用关联数组。Higgsfield 每次生成需要 3–8 分钟,务必在后台启动并轮询,切勿在前台阻塞等待。媒体参数不接受通过任务 UUID 引用文件——请为 --image/--start-image/--end-image 传入本地文件路径。不同视频模型接受的参数各不相同(例如 Kling 没有 --resolution),对起始/结束图像条件控制的支持也不同——批量生成前,请使用 higgsfield model get <job_type> 确认所选模型的参数规范,并查看第 4 步的模型表。

第 1 步 — 询问用户

主题由用户自行说明——用普通文字提出开放式问题,绝不要编造多选题。凭空列出行业选项会影响用户选择,让人觉得你在替他们决定业务;应该让他们用自己的话回答,可以是他们自己的实际业务、客户的业务,或任何想法。只有对于下方确实可枚举且影响较小的选项——艺术指导和品牌套件方案——才使用 AskUserQuestion(附选项);即便如此,也要说明用户可以另选方案(“其他”)。只询问那些无法合理设定默认值的问题。需要了解:

  1. 主题(开放式提问,不要提供选择题)——“这个世界应该讲述什么?可以是你的业务、客户的业务,或任何想法——一个词或一句话都可以。”记录行业/产品 + 一句话推介(例如“从茶叶到最后一口,一家珍珠奶茶公司”),以及品牌名称(如果已有);否则你会在下文提出一个。
  2. 品牌套件——提供三种路径,任选其一:
    • 从 URL 导入:higgsfield marketing-studio brand-kits fetch --url <site> --wait (提取名称、颜色、语气)。然后用 brand-kits list --json 读回。
    • 用户直接提供配色 + 名称 + 语气。
    • 你提出配色 + 名称,再让用户确认。 记录 4–6 个有名称的十六进制色值、一个显示名称,以及一两个描述语气的词。
  3. 美术指导——默认风格为“柔和哑光低多边形 黏土立体模型、等距视角、移轴微缩景观、暖光”。提供其他选项(扁平纸艺、亮面玩具、黏土动画、霓虹夜景)。无论选哪种,都要将其作为共享的 风格前缀,在每个场景提示词中逐字复用(这是让整个世界风格统一的关键)。
  4. **预算档位——在提出旅程前务必询问。视频生成是主要成本来源。**账单随场景数量和架构变化:架构 A(向前推进镜头)= N 个视频;架构 B(俯冲 + 衔接镜头)= 2N-1 个视频,另加 N 张静帧,以及约 20–30% 的重做缓冲。6 个场景的架构 B 生成约 17 次——会明显消耗订阅额度。使用 AskUserQuestion 并给出具体数字:
    • 精简版(约 8 次生成)——4 个场景,架构 A(4 张静帧 + 4 段镜头),跳过预演(小规模项目重做比先出草稿更省)。同一场景、同一段连续飞行——只是 4 个节拍,而非 6 个。
    • 标准版(约 11–13 次生成)——5 个场景;架构 A(10 次生成)或架构 B(5 + 9 = 14 次)。
    • 展示版(约 17 次以上生成)——6–7 个场景,完整的架构 B 世界、预演环节、移动端档位。 场景更少 ≠ 网站内容更单薄。精心挑选的 3–4 个节拍也能呈现完整的世界:为每个场景增加滚动距离(scroll: 1.6–2)并设置 linger,让文案在每个节拍承载更多信息。紧凑的 4 场景世界胜过预算不足的 6 场景世界。 如果用户想要精简预算下的 B 风格,还有两个可调整之处:衔接镜头可以单独选择是否添加(null 槽位会直接交叉淡化该接缝——需坦诚说明代价:这次转场是淡化,而非飞行;把衔接镜头留给主打场景周围的接缝);如果用户接受 720p,seedance_2_0_mini 也可以作为最终模型——它会锁定帧,因此网站仍能保持无缝衔接。
  5. 旅程(各版块)——摄像机飞越的场景顺序,应与预算档位相匹配。根据主题本身的价值链拟定一组场景,并让用户编辑。珍珠奶茶示例(展示版,6 个场景):茶园 → 珍珠制作厨房 → 旗舰店 → 配送 → 社区广场 → 主打产品;精简版(4 个场景):茶园 → 厨房 → 店铺 → 主打产品。每个版块都需要:简短的主题描述(立体模型中有什么)、眉题、标题、一行正文,以及 0–3 个标签胶囊。最后一个版块通常展示主打产品 + CTA。
  6. **移动端档位——务必询问;绝不要悄悄生成额外素材。**所有档位的手机端都会使用完整的滚动动画——引擎的强化机制(seek 合并、iOS 预热 + 低电量模式静帧回退、安全区域 CSS、数据节省模式降级)始终启用;档位只决定会生成哪些素材。使用 AskUserQuestion,按以下顺序提供选项,并注明积分成本:
    • 适配裁切(默认,无额外成本)——手机播放桌面版片段,并居中裁切为竖屏。每个提示词本就会将焦点主体安排在中心安全区域(prompts.md),因此大多数世界都能正常呈现。
    • 移动端编码(推荐,不额外消耗积分,只需编码时间)——生成 -m.mp4 配套文件(720p、-g 4,第 6 步),添加 clipMobile/connectorsMobile/posterMobile 接线(第 7 步),并进行移动端 QA(第 8 步)。手机级设备(不是平板——引擎按屏幕尺寸划分档位,iPad 使用主版本)播放较轻量的文件。
    • 主打场景重构(少量额外积分——请说明)——移动端编码 + 对焦点主体无法适应居中裁切的 1–2 个场景重新渲染为 9:16(通常是主打场景 + 结尾场景)。按场景接入移动端片段/海报图。
    • 完整竖屏链路(金牌档,视频积分约翻倍——请说明)——并行生成一套 9:16 链路:竖屏静帧、独立的帧交接、独立的衔接镜头、独立的 SSIM 门控(宽高比不能在链路中途混用——9:16 片段无法从 16:9 帧继续)。这是 Apple 发布的方案:移动端素材是采用不同构图重新渲染的版本,而非裁切版本。仅当用户表示移动端流量很重要,或预算充足时才提供此选项。 视频模型不是采访问题——默认静默使用 seedance_2_0。如果用户指定了偏好,仅当该模型支持帧锁定衔接时才予以采纳(Step 4 名单:seedance_2_0、kling3_0、seedance_2_0_mini)。此技能只生成无缝输出,因此不支持帧锁定的模型会被拒绝,并用一句话说明原因,不会替用户擅自换用;请改用名单中的模型。

结束采访时给出费用估算——开始生成前必须获得明确同意。 根据所选预算档位,用直白的数字说明费用:N 次图像生成 + 视频生成(架构 A 为 N 次,架构 B 为 2N-1 次;展示运行还会增加一组 mini 档位的预演链)+ 返工预算(室内场景约额外增加 20–30%,这是由于 NSFW 过滤器所致),以及任何移动端档位的额外费用,并估算大致耗时(每次生成需 3–8 分钟;架构 A 为顺序执行)。用户只需在此处批准一次费用——之后仅有两个确认关卡:锚点静帧审批(Step 2)和预演审核(Step 4),这两个关卡是为了避免浪费大笔费用,而不是再次征求许可。

固定滚动机制(连续飞行穿越)——这是此技能的核心。请参阅 references/prompts.md,了解信息收集清单和副本结构。


Step 2 — 生成场景静帧

每个分区生成一张图,所有图共用相同的风格前缀以保持一致。默认模型为 gpt_image_2(画面清晰,特别擅长等距插画;生成纯色/白色背景,非常适合悬浮立体微缩场景“岛屿”)。仅当需求以角色/卡通为主时才使用 nano_banana_2(注意:nano_banana_2 是 CLI 别名——它实际对应 nano_banana_pro;在 higgsfield model list 中不会以该名称出现)。

提示词结构(完整模板见 references/prompts.md):

<STYLE PREAMBLE, identical every time>. On a plain solid <bg> background with a soft
contact shadow. <PALETTE hexes>. No text, no letters, no logos, centered, 3:2.
Subject: <what is in THIS diorama>.
  • 先生成锚点——绝不要一次性冷启动批量生成全部 N 张。 先生成一张锚点静帧(最具代表性的场景),展示给用户,并反复调整风格前缀,直到用户批准。只有在此之后,才能将其余 N-1 张批量生成,并通过 --image 传入已批准的锚点以锁定风格。锚点风格不符合预期只需花费 1 次生成;冷启动批量生成后再调整则要花费 N 次。这是硬性关卡——锚点未经批准,不得继续。
  • 并发、脱离终端地批量生成其余场景。每个场景使用以下命令: higgsfield generate create gpt_image_2 --prompt "$(cat scene_i.txt)" --image anchor.png --aspect_ratio 3:2 --resolution 2k --quality high --wait --wait-timeout 15m --json > scene_i.json 2>scene_i.err
  • 结果 URL 位于 --wait --json 输出中的 .[]0.result_url。用 curl 下载。
  • 生成可能会暂时失败(HTTP 503)——单独重试该项;不要重新启动整个批次。
  • 继续之前先审核整个批次。 所有场景应呈现为一个连贯的世界(角度、调色板、光线一致)。对任何风格不符的场景单独重试——锚点的风格锁定继续生效。

请参阅 references/pipeline.md,了解准确的批量处理脚本(支持幂等——重新运行会跳过已完成的资源,因此即使崩溃或重试,也不会为已完成的工作再次付费)。


Step 3 — (可选)让场景悬浮

如果希望立体微缩场景悬浮在氛围背景上,而非置于纯色方框中,可使用 references/knockout.py 将纯色背景抠为透明(基于边界连通的泛洪填充——会保留与背景颜色相同的内部区域,例如奶油色墙壁)。然后编码为 webp。如果想简化处理,只需将页面背景设为与场景背景相同的颜色,并跳过此步骤。

无论如何都要保留静帧——它们是减少动态效果时的插画,以及无片段时的后备方案。(加载海报不是静帧:它们会在 Step 6 从编码后的片段中提取,因此静帧切换到视频时不会出现突变。)


Step 4 — 摄像机架构(选择一种——这决定整体观感)

摄像机在场景之间的移动方式,是影响质量的最大因素。共有两种形式;按审美偏好选择。

视频模型 — 为整条链选择一个

此技能只提供无缝输出,因此只有能够锁定接缝帧的模型才可用:每个串联片段都必须支持 --start-image,连接片段还需要 --end-image。选择标准是这种能力,而非偏好。使用 higgsfield model get <job_type> 检查模型,并跳过媒体输入仅限参考图的模型(没有起始图像/结束图像):它们只能为生成提供条件,不能延续镜头,因此从技术上就无法保持接缝。以下架构已通过 CLI 确认:

模型起始图像/结束图像备注
seedance_2_0(默认)✓ / ✓完整链路(片段 + 连接片段)。使用 --mode std --resolution 1080p。它的 NSFW 过滤器最敏感(见注意事项)。
kling3_0✓ / ✓完整链路 — 已测试:--mode std --sound off --duration 5 接受起始图像 + 结束图像,接缝可干净地锁定帧。没有 --resolution 参数(不要传入;--mode std 返回原生 720p — 按 ffprobe 报告的分辨率编码,绝不升频)。声音默认开启 → --sound off。--duration 默认值为 5,片段可尝试设为 10。内容过滤器与 Seedance 不同 — 经认可的 NSFW 备用方案。
seedance_2_0_mini✓ / ✓低成本草稿档,同时保持帧锁定(720p)。预演档:先在这里运行整条链,然后用完整模型重新渲染最终片段 — 仍然无缝,因此可直接用于成片。

以上三款就是候选模型 — 都支持这两种架构。(kling3_0_turbo 也可通过 --start-image 锁定帧,但不支持 --end-image,所以仅适用于架构 A,无法生成连接片段;它使用的标志也不同 — 没有 --mode,但有 --resolution — 因此无法直接用于当前流水线。它不在默认候选名单中;只有在架构 A 的顺序渲染时间已确认成为瓶颈,且基准测试证明它确实更快时,才考虑手动接入。)

先做预演(默认要求,不是可选项)。 除非本次运行规模较小(≤4 个场景),否则先用 seedance_2_0_mini 渲染整条链。它支持帧锁定,因此所有关键内容 — 旅程顺序、镜头语法、接缝连续性、文案相对于拖动进度条的节奏 — 都能以草稿成本完成验证;先用预演片段组装页面并交由用户审核,再花费任何完整模型额度。之后清除草稿片段,切换 $VMODEL,重新渲染成片(静帧会复用;流水线的幂等性让第二遍执行变成机械流程 — 参见 references/pipeline.md 的 setup 部分)。

规则:

  • 整条串联链使用同一个模型。 每个渲染器都有自己的运动/色彩/颗粒特征;在链中途混用模型可以保持位置连续性(帧仍能衔接),但渲染特征的变化会产生轻微跳变。唯一经认可的例外是对单个顽固片段使用 NSFW 备用方案(见注意事项)— 一个 5 秒连接片段略有特征变化,也好过缺少连接片段。
  • 默认使用 seedance_2_0;只有模型符合条件(支持帧锁定)时,才遵从用户明确提出的偏好。如果不符合,要说明原因并改用受支持的模型 — 绝不能为了满足模型要求而交付非无缝成片。
  • 流水线脚本通过 $VMODEL 接收模型,并已针对每个模型配置好标志(references/pipeline.md)。
A) 连续向前镜头 — 推荐用于真实感强、贴近现实或逐步讲解的场景

一台摄像机从第一个场景到最后一个场景始终只向前方滑行,一镜到底。 按顺序生成各段:第 0 段从场景 0 的静帧开始(向前滑入场景); 之后每段的 --start-image = 上一段的实际最后一帧(用 ffmpeg 提取),提示词使用 "继续平稳地向前滑入[场景 i],绝不后退" (或在运动交接规范下使用富有表现力的段中运镜——参见下文的摄像机运镜语法), 并且不使用 --end-image——宽广的全景建立镜头会迫使摄像机后退,这是造成卡顿的首要原因。提取每段的最后一帧,供下一段使用。结果是:每个衔接处的画面完全一致,而且摄像机从不反向移动。这里没有连接镜头(跳过第 5 步)——各段本身就是整段旅程。将每段接入为一个带 connectors: [] 和较短 crossfade(约 0.08)的分段片段。即使没有 --end-image,各段仍会抵达不同的房间(提示词会引导画面内容)。代价:必须顺序生成(无法并行处理),速度较慢;室内场景会触发 NSFW 过滤器,因此要预留重试次数(每段尝试 3 次)。

B) 下潜镜头 + 航拍连接镜头 — 仅用于立体模型/微缩模型/上帝视角世界

生成一个“下潜进入每个场景”的片段,再生成一个向上并向外拉远、飞往下一个场景的连接镜头(第 5 步)。拉远会在每个衔接处反转摄像机方向(向前下潜 → 向后拉远)。在微缩模型/立体模型世界里,这种效果看起来像是有意为之的“缩小视角回到地图,再飞往下一个岛屿”;但在贴近现实的第一人称漫游中,则会显得像倒带/卡顿一样突兀。仅在地图式美学中使用 B。不确定时,使用 A。

摄影机运镜语法——运镜应契合概念(A 并非“只能向前”)

“只能向前”是接缝规则,不是单段规则。运镜链的物理逻辑如下:

  • 接缝处的位置连续性来自帧交接(下一段从上一段的实际最后一帧开始)。
  • 接缝处的速度连续性意味着摄影机绝不能跨越接缝反向运动——那会造成回放卡顿。
  • 单段内部,摄影机可以自由运动。 一段是一次连续渲染——中途没有接缝,因此环绕、升臂上移、横向跟拍,甚至先推进再缓缓拉回,都可以在片段内部安全使用。只有跨越接缝的反向运动才会造成问题。

因此,应根据场景自身的逻辑,为每段选择富有表现力的运镜,并遵循一份运动交接约定:每段结束时都要平稳收束为朝下一个目的地缓慢、匀速向前漂移(最后约 1 秒),且每段开始时都要延续相同的漂移。在提示词中逐字保留这两条要求(模板见 references/prompts.md)。

根据概念选择运镜语法:

概念 / 基调单段中段运镜
产品 / 奢侈品零售围绕主打物体缓慢环绕半圈,然后继续向前掠过
房地产 / 酒店服务稳定器镜头滑过门口;在中庭轻柔升臂上移
工业 / 流程 / 物流沿生产线低位横向跟拍,营造前景视差
旅行 / 户外 / 校园无人机式升高并展现景观,然后俯冲下降
美食 / 手工艺 / 注重细节推近拍摄手艺展示的瞬间,缓缓拉回,再继续前行
趣味微缩场景(arch. B)俯冲 + 空中跳跃——连接段本身就是运镜语法

务实考虑:富有表现力的单段运镜会增加重拍概率——模型可能以不符合干净向前漂移的状态结束复杂运镜。应对方法:逐字保留最后一秒的收束要求;串接下一段前,仔细查看每段的最后一帧(画面应像是从容向前滑行中的一帧——否则就在浪费下一段之前重拍);每段富有表现力的运镜预留约 1 次额外重拍。朴素的向前滑行仍是零风险默认选项——场景本身就是看点的段落就用它。

引擎中还有两个相关的节奏控制项(步骤 7):每个章节的 scroll(滚动距离越长,在该场景停留越久)和 linger(摄影机在文案达到高潮时恰好于场景中段停留,随后加速驶向接缝)。运镜表达力优先放在片段中,滚动映射则保持克制——两者效果会叠加。

还要记住,滚动是一种擦动控制:访客可以向上滚动,因此每种运镜也会反向播放。这是免费且符合预期的——无需额外处理——但也再次说明接缝速度必须在两个方向上都保持一致(正向播放时看起来没问题的接缝,如果速度发生反转,反向播放时同样会显得卡顿)。

对于 B,每个场景只进行一次摄影机飞行:从高处、外部开始,下降进入内部,结构随之打开。模型:使用你在上文选定的链模型(默认 seedance_2_0),--start-image = 场景静帧。

  • 使用纯背景静帧(而不是抠出的透明背景版本)作为起始图像,这样视频才会有完整画面。
  • 提示词:“单次连续的电影感运镜,不要剪辑。从高处远距离开始,从外部俯瞰整个 ……下降并飞入内部,朝 前进……屋顶 / 墙壁轻柔打开,展现内部空间。,平滑优雅的慢动作。不要文字。”(模板见 references/prompts.md。)
  • 参数(seedance):--mode std --resolution 1080p --aspect_ratio 16:9 --duration 8。对于 Kling:移除 --resolution(没有此参数),添加 --sound off、--duration 10。不要传入 --generate-audio(seedance 会报错;反正音频也没用——你会静音)。
  • 并发运行并置于后台,然后下载每个 .result_url。单独重拍失败项。保留原始 1080p 源文件——接下来需要从中提取帧。

第 5 步 — 连接片段(仅适用于架构 B)

架构 A 可跳过整个步骤——正向推进的镜头没有连接片段;各段本身就能无缝衔接。此步骤适用于 B(立体模型/微缩场景),并请注意第 4 步提到的反转注意事项。

连接片段能让世界显得彼此相连,而非被切断。连接片段从场景 i 的结尾飞出,再进入场景 i+1 的开头。它的两个端点都必须是相邻片段实际渲染出的画面帧——绝不能用原始的立体模型静帧。

原因:Higgsfield 的每次生成渲染结果都会略有不同。如果连接片段结束于新渲染的“厨房立体模型”,而下一个俯冲片段开始于它对同一立体模型的另一种渲染结果,两者就无法匹配,衔接处会突然跳变。解决方法是传递完全相同的像素:

For each connector between dive_i and dive_{i+1}:
  start-image = the LAST frame extracted from dive_i's rendered video
  end-image   = the FIRST frame extracted from dive_{i+1}'s rendered video

现在,每个衔接处的两侧画面帧都完全相同: dive_i.end == connector.start 且 connector.end == dive_{i+1}.start。

从渲染后的俯冲片段中提取边界帧(而不是从静帧中提取):

ffmpeg -sseof -0.15 -i dive_i.mp4   -frames:v 1 -q:v 2 dive_i_last.png    # interior of i
ffmpeg -ss 0      -i dive_{i+1}.mp4 -frames:v 1 -q:v 2 dive_next_first.png # establishing of i+1

生成连接片段(--duration 5 就足够了)。连接片段需要 --end-image,因此模型必须支持它——所有候选模型都支持(seedance_2_0、seedance_2_0_mini、kling3_0):

higgsfield generate create "$VMODEL" \
  --prompt "$(cat connector_i.txt)" \
  --start-image dive_i_last.png --end-image dive_next_first.png \
  $VOPTS --aspect_ratio 16:9 --duration 5 --wait --json
# seedance: VOPTS="--mode std --resolution 1080p"; kling3_0: VOPTS="--mode std --sound off"

连接片段提示词:“单次连续的镜头运动,不要剪辑。从 向上升起并向后拉远,升入天空,掠过彼此相连的微缩世界,抵达 <scene i+1> 上方,并开始向下俯冲。流畅无缝的空中转场。。不要文字。”(模板见 references/prompts.md。)

保险措施:Seedance 生成的画面会接近结束图像,但不一定与其像素完全一致,因此引擎仍会在每个衔接处应用短暂的交叉淡化(几帧)。端点帧匹配 + 短暂交叉淡化 = 看不到切换。绝不要跳过实际帧交接,只依赖交叉淡化;内容差异太大,交叉淡化也无法掩盖。

交接是否成功可以通过机器检查——不要等到浏览器 QA 才发现问题。编码后,运行 SSIM 衔接检查(references/pipeline.md §5c):实际帧交接的得分在边界处应 ≥0.95;<0.75 表示端点使用了静帧或错误的画面帧。每次重新生成后都要再次运行检查——替换一个片段会悄然影响它两侧的两个衔接处。


步骤 6 — 编码以实现流畅拖动

拖动 = 根据滚动设置 video.currentTime。有两点很重要,而且经常被弄错:

  1. 拖动是否流畅取决于可寻址性,而非关键帧密度。 许多静态主机(以及 python -m http.server)不支持 HTTP 字节范围请求,导致 video.seekable 固定为 [0,0],并将每次寻址都限制在第 0 帧——视频看起来像是卡住了。稳妥的解决方法是将每个片段获取为 Blob,并通过内存中的对象 URL 播放(Blob 始终完全可寻址)。引擎采用了这种做法。因此,不需要全帧内编码视频。
  2. 不要为了流畅寻址而降低画质。 以原生分辨率编码(Seedance 输出的 1080p——不要缩小),crf ~20,使用较小的 GOP(-g 8),而不是全帧内编码(全帧内编码会让一个 8 秒片段膨胀到约 25 MB;GOP 8 约为 8 MB,通过 Blob 拖动也很流畅)。移除音频,添加 faststart,并使用轻度 unsharp 来改善视频的柔和感:
ffmpeg -i src.mp4 -an -vf "unsharp=5:5:0.8:5:5:0.0" \
  -c:v libx264 -preset slow -crf 20 -pix_fmt yuv420p \
  -g 8 -keyint_min 8 -sc_threshold 0 -movflags +faststart out.mp4

用相同的设置编码全部 2N-1 个片段(潜入片段 + 连接片段),以保证画质一致。

从编码后的片段中提取海报帧(references/pipeline.md §5b)。静帧是 3:2 图像;片段则是该图像的 16:9 重新渲染版本——如果将静帧用作加载海报,访客看到的第一个场景在视频首次渲染时会明显跳变(裁剪 + 渲染偏差)。连接片段也遵循同一原则,这里将其应用于第 0 个接缝:海报必须是从片段中提取的首帧。将其接入 sections[k].poster(步骤 7);静帧则保留为减少动态效果时使用的画面。

然后,在打开浏览器之前运行自动接缝检查(references/pipeline.md §5c)——每个接缝的 SSIM 都必须 ≥0.90,否则就需要重做,而不是记作一条 QA 备注。

移动端编码(仅当用户在步骤 1.6 中选择了高于安全裁剪的档位时)。 手机视频解码器的寻址速度远慢于笔记本电脑,而且寻址成本会随 GOP 长度增加,因此在桌面端拖动流畅的 1080p -g 8 母版,在手机上可能会卡顿。为每个片段生成较轻的 -m.mp4 版本——720p、-g 4(关键帧越多,寻址成本越低;每 4 到 10 帧一个关键帧是让移动端视频拖动流畅的行业惯例),crf 23——并将其接入 clipMobile / connectorsMobile(步骤 7)。将每个移动端编码的首帧提取为其 posterMobile(与 §5b 遵循相同原则——海报必须与设备实际获取的编码版本匹配)。引擎仅在手机级设备上提供移动端文件(屏幕短边 ≤600 CSS px;平板和 iPad 使用母版),没有移动端文件时则回退到桌面片段。脚本见 references/pipeline.md §6;英雄镜头重构 / 竖屏链档位见 §7。如果用户选择了安全裁剪,则跳过此步骤——引擎仍会全面优化手机端拖动(合并寻址请求、iOS 预加载、低电量模式静帧回退),因此页面会平稳降级,而不会出错。


第 7 步 — 组装页面

将 references/scrub-engine.js(如果想要一个完全独立的页面,也可将精简的 references/index-template.html)复制到用户的项目中,或改编为适用于其 框架的版本。它由配置驱动且独立完整:

mountScrollWorld(document.getElementById('world'), {
  brand: { name: 'Pearl & Co.' },
  diveScroll: 1.3, connScroll: 0.9,          // viewport-heights of scroll per clip
  sections: [
    { id:'farm', label:'The Farms', still:'assets/farm.webp',
      poster:'assets/farm-poster.webp',          // encoded clip's extracted first frame (Step 6)
      clip:'assets/vid/farm.mp4', clipMobile:'assets/vid/farm-m.mp4',   // mobile beta only
      scroll: 1.6, linger: 0.45,   // optional pacing: longer dwell + camera settles mid-scene
      accent:'#8FB98A', eyebrow:'From leaf to last sip', title:'It starts in the hills.',
      body:'…', tags:['Single-origin','Hand-picked'] },
    // …one per section; last may carry a `cta`
  ],
  connectors:       ['assets/vid/conn1.mp4','assets/vid/conn2.mp4',   /* … length = sections-1 */],
  connectorsMobile: ['assets/vid/conn1-m.mp4','assets/vid/conn2-m.mp4' /* … same length; mobile beta only */],
});

引擎负责:有序的潜水/连接器链、通过 rAF 平滑处理滚动→currentTime、加载 blob、预取附近片段、帧匹配交叉淡化、每个分区固定显示文案(首个分区在落地时问候,最后一个分区保持显示 CTA)、路线栏、 prefers-reduced-motion 和移动设备适配。每个分区的节奏:scroll 会覆盖该场景的 diveScroll(滚动距离越长,停留时间越久);linger(0–1,保持 ≤ 0.6) 会重新映射时间,让摄像机在场景中途稳定下来——恰好与文案达到高潮的时刻重合——随后加速驶向接缝;接缝帧不受影响(f(0)=0,f(1)=1)。为主视觉和收尾场景设置更大的 scroll 值和一些 linger;过场场景则保持轻快。使用 CSS 变量设置主题(--accent、 --sw-bg、--sw-ink,等等)——视觉标识来自生成的片段,因此界面装饰应保持低调。完整配置和 CSS 变量见 scrub-engine.js 的文件头。

在手机上,引擎会沿两个独立维度自动适配。 片段规格 (使用哪个文件)由设备类别决定——屏幕较短的一边 ≤600 CSS px 即为手机 → 使用 clipMobile/posterMobile;平板(包括 iPad Pro——尽管采用粗指针,但屏幕和解码器属于桌面级)及桌面设备使用主版本。行为强化 (如何运行)则根据粗指针 / ≤860px 视口决定:合并 seek 操作(seek 过程中绝不排队新的 currentTime——这能避免快速滑动导致片段卡住)、片段开始绘制前保留海报图、首次触摸时预热视频(修复 iOS 上播放前画面空白的问题)、每个场景延长滚动时长(scrollMobileFactor,默认 1.2——小视口中相同的飞行会显得更快)、移除粒子、规避网址栏导致的尺寸变化、安全区域内边距。自动静帧回退:prefers-reduced-motion、 Chromium 的省流量模式,以及 iOS 的低电量模式(运行时检测——首次触摸时静音的 play() 调用遭拒)都会让页面改用带交叉淡化的静帧,而不是冻结的视频。在 2g/3g 网络上(Chromium 信号),片段预取窗口会缩小。以上功能默认启用——无需配置。clipMobile/connectorsMobile/posterMobile 编码是第 1.6 步中的可选规格:只有用户选择了相应规格时才接入。

SEO 文案不可省略——这是一个落地页。 引擎会在客户端渲染所有文案,因此页面本身没有任何可供抓取的文本。务必在容器中通过 data-sw-seo 块加入文案的纯标记副本(h1 = 主视觉文案,每个场景各有一个 h2 + p,以及真实的 CTA 链接)——引擎挂载时会将其隐藏,爬虫/链接预览/未启用 JS 的访客则能从服务器返回的 HTML 中读取。references/index-template.html 已包含此块;改编到框架中时,请在服务器端渲染该内容。

对于非 JS 后端(Python/Rails 等):提供这些资源,并将引擎 <script> 放入渲染后的 HTML;它不依赖任何特定框架。


步骤 8 — 检查衔接处(不要跳过)

先进行机器检查: SSIM 衔接处关卡(references/pipeline.md §5c)必须已经通过——每处衔接的 SSIM 都 ≥0.90(仅在你亲自检查并接受交叉淡化的情况下,才允许为 0.75–0.90)。如果跳过了,现在就运行;下面的浏览器 QA 用于验证页面,SSIM 关卡用于验证素材,素材不合格,页面就不可能通过 QA。

然后在无头浏览器中操作页面,并端到端验证衔接处的帧连续性:

  • 在每处衔接前后刚好滚动到的位置截图。这两帧必须几乎一致(潜入片段的最后一帧 == 连接片段的第一帧)。如果画面突变,说明你用的是场景模型静帧,而不是真正渲染出的帧(重做步骤 5);或者交叉淡化区间太短。
  • 确认首次绘制干净:海报帧(提取出的帧)立即显示,且海报帧→视频接管时图像不会位移(如果位移,说明缺少 poster 或它指向静帧——步骤 6)。
  • 检查控制台是否有错误,确认 video.seekable.end(0) > 0(blob 正常工作),并确认 currentTime 会随各片段区间内的滚动而变化。
  • 静帧模式回退(每次构建都检查,成本很低):
    • 数据节省模式:模拟 navigator.connection.saveData = true(使用 DevTools 覆盖或初始化脚本)——页面必须以静帧交叉淡化方式渲染,Network 面板中不得有片段请求。
    • 低电量模式:最难模拟——在真实 iPhone 上启用此模式,并确认页面在首次触摸时回退到静帧,而不是冻结的视频。模拟代理方案:将 HTMLMediaElement.play 替换为返回已拒绝 Promise 的实现,点击并确认进入静帧模式。
    • 平板档位:iPad 视口(834×1194,触控)必须请求桌面版片段(Network 面板),而不是 -m.mp4,同时仍保留触控行为。
  • 移动设备——仅当用户选择了移动档位时,才执行完整检查清单(步骤 1.6)。 对于裁切安全构建,只需在手机视口下进行一次基本检查:页面能加载、静帧海报能显示、没有元素重叠——引擎的强化处理可确保优雅降级。 对于移动档位(在真实手机或模拟设备上执行,测试竖屏和横屏):
    • 模拟手机视口,将 CPU 限速至 4–6 倍并快速滚动——片段应能跟随滚动,不会冻结(寻帧合并 + -m.mp4 编码能确保这一点)。
    • 确认首个场景立即显示(其静帧就是海报),并在开始滚动时视频立即接管——不能出现空白或黑屏场景(iOS 预热修复)。特别测试 iOS Safari;此问题回归时只有它会出现空白。
    • 验证移动设备实际提供的是 -m.mp4 变体(Network 面板),而桌面端提供的是 1080p 大师版。
    • 缓慢滚动,让 URL 栏收起——页面不得跳动(触摸操作中忽略仅高度变化)。旋转设备——布局应能干净地重新排布。
    • 竖屏会将 16:9 片段裁切至中心;确认焦点主体仍清晰可辨。如果英雄场景的主体偏离中心而被裁掉,请重新构图(prompts.md),或为该场景生成 9:16 变体。
  • 检查减少动态效果设置(应回退到静帧,不播放视频,也不显示粒子)。

注意事项 — 前 5 项内联列出;完整列表见 references/gotchas.md

任何生成失败或 QA 检查结果异常时,请立即阅读 references/gotchas.md——其中列出了生产环境中遇到的每种故障的症状 → 原因 → 解决方法(编码、主题、手机、iOS、Kling 参数、肖像裁切等)。最常导致运行受阻的 5 项:

  • 接缝处跳变 → 连接器端点使用的是场景模型静帧,而非相邻片段的实际画面。务必提取真实帧(步骤 5);SSIM 门禁(pipeline §5c)会在打开浏览器前检测到此问题。
  • 接缝处卡顿/镜头“向后跳” → 镜头速度在接缝处反向(架构 B 的拉远镜头固有的问题)。实景漫游必须使用架构 A(步骤 4)。
  • NSFW 误报(Seedance status "nsfw") → 会将无害的室内场景标记为违规(卧室/泳池/水疗场所;以及 "bed"、"wine"、"swim" 等词)。按以下顺序处理:重新生成(通常第 2~3 次就能通过)→ 删除触发词,并添加 "empty, unoccupied, no people, architectural" → 使用相同的起始帧和结束帧,在 kling3_0 上重新生成该片段 → 将连接器槽设为 null(引擎会直接交叉淡化该接缝)。为室内场景预留重新生成的次数。
  • 视频冻结/卡在第 0 帧 → 主机不提供字节范围请求,seekable=[0,0]。Blob URL 可以解决此问题(引擎会自动处理)。
  • 并发生成返回 503/出现 "not_enough_credits" 竞态 → 并行启动时可能暂时发生;重新生成失败的那一项(使用 higgsfield workspace list 验证点数)。

参考资料

  • references/prompts.md — 输入检查清单、风格前缀模式,以及所有带填充槽的提示词模板(场景静帧、潜入镜头、连接器)。
  • references/pipeline.md — 覆盖完整运行流程的可复制粘贴批处理脚本(锚点门控静帧 → 预览 → 潜入镜头 → 帧 → 连接器 → 编码 → 海报 → SSIM 接缝门禁 → 移动端编码),支持幂等执行且兼容 bash-3.2。
  • references/scrub-engine.js — 可移植、由配置驱动的 scrub 引擎(构建 DOM + 注入 CSS;Blob 定位、延迟加载、接缝交叉淡化、提取帧海报、隐藏的 data-sw-seo 静态文案块、复制、路线导航栏、减少动态效果,以及针对手机的强化处理:移动端编码、定位请求合并、iOS 预热、安全区域、调整大小时避免跳动)。
  • references/index-template.html — 用于挂载引擎的最简独立页面,包含可供爬虫抓取的 data-sw-seo 文案块。
  • references/knockout.py — 用于悬浮场景的边缘连通背景抠除。
  • references/gotchas.md — 完整的症状 → 原因 → 解决方法列表,以及在视频拖动不够流畅时可用的画布帧序列替代方案。

评论

支持 Markdown