晾衣绳英雄区(Washing Line Hero)
网站的第一屏:品牌栏和导航在上方,一行大标题(其中某个短语带有颜色),一行简介文字,一至两个按钮和一行小注,旁边是横跨天际的晾衣绳。绳上挂着一条由木夹固定的棉布,印有品牌自己的海报:一个名称、一行小字、两个大字、一列规格说明和一个小柱状图。微风不时吹起布料,云朵在后方缓缓飘移。
它旨在被触摸。将指针移到布料上,指尖会按压出凹陷。按下并拖拽,布料会随手移动:拉起一角,折叠过绳,朝向自己拉伸。松手后,布料会下落、摆动并归位。在手机上,手指操作相同,且握持布料时页面不会滚动。布料是模拟的(由粒子网格通过拉伸、剪切和弯曲约束构成,以固定的120Hz步进更新),因此布料在被抓取的任何位置都会像真实织物一样表现,而非播放预设动画。
你通过 hero.json 描述英雄区和印刷内容。构建过程会检查所有内容,并写入 out/index.html(一个单文件完整页面)以及 out/embed.html(可粘贴到已有网站中的同一区域)。由于模拟从静止起点开始以固定步进运行,record.mjs 可以逐帧步进:视频中,一个绘制的手指针拉起一角,松手,然后用指尖掠过布料表面,展示访客可以执行的操作,且在所有机器上效果一致。
它不是:布料不会撕裂、自缠或吹离晾衣绳(没有自碰撞,所以如果强行折叠穿过自身,它会穿过并落回),印刷内容由页面根据你的文本绘制,而非上传的照片。
你需要什么
- Node.js 18 或更新版本。无需安装其他内容。
- Chrome、Chromium 或 Edge,用于检查与录制(脚本会自动查找;若找不到,请设置
CHROME_PATH)。 - ffmpeg,用于视频(
brew install ffmpeg、winget install ffmpeg或apt install ffmpeg;也可设置FFMPEG_PATH)。 - 页面打开时的互联网访问:three.js 和字体从 jsDelivr 以固定版本加载,并带有完整性哈希。无网络时,访问者将看到静态图片(同一晾衣绳和布料,平面绘制)和系统字体;页面仍可正常工作。
此技能的文件夹为 <skill>(即本 SKILL.md 文件所在的文件夹)。
步骤
1. 收集品牌与文案
向对方询问,或在其现有网站上查找:
- 品牌名称 和 Logo(SVG 文件,正方形或近似,简单无脚本的版本)。若没有,最多三个字母组成字母组合。
- 颜色:背景色(同时也是地平线处的天空色;文本颜色必须与其达到 7:1 对比度)和一种强调色。浅蓝色营造正午天空搭配深色文字的效果;深蓝或紫黑色营造黄昏天空搭配浅色文字和低暖阳的效果。
- 字体:一种显示字体用于标题和布料上的大字,另一种用于其余文字。以下字体已固定版本加载并经过校验:Space Grotesk、Inter、Instrument Sans、Instrument Serif、DM Sans、Manrope、Fraunces、Sora、Outfit、Bricolage Grotesque、IBM Plex Sans、JetBrains Mono、Plus Jakarta Sans、Newsreader、Playfair Display。其他 Google Fonts 系列也可使用,但未固定版本。
- 页面上的文案:一个标题(其中某个短语需着色)、一或两句说明(介绍什么内容、面向谁)、主按钮和可选的第二个按钮(指向目标位置)、最多五个导航链接和栏内按钮。标题上方的小徽章和按钮下方的小注为可选项。
- 布料上的文案:顶部印制的名称(通常是产品名称和版本)、其下的一行小字、两到四个大字(两行效果最佳)、最多六个简短规格对(标签和值)、图表的标题以及角落的网址。
每个名称、数字、主张和日期必须来自对方。不要自行发明规格或数据;宁可省略规格。图表的柱状图是从种子中绘制的装饰性元素,而非数据:请为其添加一个不声称数字的标题,或者将其关闭。
2. 编写 hero.json
复制最接近的示例文件夹并替换所有内容:examples/paperwind/(一个笔记应用,浅色正午天空,四个夹子)或 examples/halden/(一个亚麻品牌,黄昏天空,三个夹子,更方形的布料)。
| 字段 | 说明 | 限制 |
|---|---|---|
brand.name、brand.href | 左上角品牌名称及其链接(默认 /) | 28 |
brand.logo | 一个与 hero.json 同目录的 .svg 文件,内联到页面中;或最多 3 个字母组成字母组合 | – |
nav[] | 最多 5 个 { "label", "href" },以药丸样式显示(手机上隐藏) | 18 |
action | 右上角按钮 { "label", "href" };false 表示无 | 22 |
hero.badge | 标题上方的一行小型大写字母文字 | 40 |
hero.title | 标题。*短语* 将其设置为强调色;\n 换行(最多 3 行) | 72 |
hero.lede | 说明(什么内容、面向谁)。内联 Markdown:代码、链接、加粗、斜体 | 220 |
hero.actions[] | 1 或 2 个 { "label", "href" }:第一个是带箭头的实心主按钮,第二个是描边按钮 | 26 |
hero.note | 按钮下方的一行小字 | 90 |
hero.align | left(晾衣绳和布料在右侧,默认)或 right(镜像)。center 将布料放在文案后方;不推荐 | – |
theme.background、theme.ink、theme.accent | 十六进制颜色。ink 必须与 background 达到 7:1 对比度 | – |
theme.mode | light 或 dark;未设置时根据背景自动判断 | – |
theme.fonts | { "display", "body", "weight" }:字体家族名称(false 表示系统字体)和标题字重(300–800,默认 500) | – |
theme.scrim | 0–1:文案后方天空被洗白为背景色的强度。默认 0.3 | – |
effect | 天空、晾衣绳和布料,详见下文 | – |
motion.speed | 0.25–2,默认 1:所有元素运动速度 | – |
motion.pointer | true(默认) | – |
meta | title(70)和 description(170)用于搜索和链接预览;url 和 image(完整 https 地址)、lang(默认 en) | – |
印刷内容(effect):至少包含 printTitle 或 printHeadline。
| 设置 | 限制 | 默认 | 说明 |
|---|---|---|---|
printTitle | 28 字符 | 无 | 印刷内容顶部的名称 |
printLine | 64 字符 | 无 | 名称下的一行小字 |
printHeadline | 48 字符 | 无 | 大字;\n 换行。文字会缩放以适应列宽 |
printSpecs | 0 到 6 个 { "label", "value" },分别为 12 和 14 字符 | 无 | 右侧的规格列;标签以大写字母显示 |
printChart | true / false | true | 规格下方的小柱状图,最高柱使用 theme.accent 颜色 |
printChartLabel | 32 字符 | 无 | 图表下方的标题 |
printFoot | 40 字符 | 无 | 底角小字,例如网址 |
cloth | 颜色 | #ecebe6 | 布料颜色 |
printInk | 颜色 | #15181d | 印刷内容颜色。必须与 cloth 达到 7:1 对比度 |
场景(effect),所有设置均为可选:
| 设置 | 范围 | 默认 | 作用 |
|---|---|---|---|
seed | 1–9999 | 7 | 种子,用于云朵和图表柱状图 |
skyTop | 颜色 | #5f9be0(浅色模式),背景变暗(深色模式) | 英雄区顶部的天空颜色 |
skyBottom | 颜色 | theme.background | 地平线处的天空颜色 |
clouds | 0–1 | 0.6 | 天空中被云覆盖的比例;0 为晴朗 |
cloudColor | 颜色 | 白色(浅色模式),柔和紫灰色(深色模式) | 云朵颜色 |
drift | 0–1 | 0.35 | 云朵飘移速度 |
light | day、dusk | 浅色模式为 day,深色模式为 dusk | 正午阳光从上照射,或低暖阳与冷色调天空光 |
aspect | 0.8–1.7 | 1.35 | 布料宽度与高度之比 |
pegs | 2–6 | 4 | 顶部边缘的木夹数量 |
peg | 颜色 | #c39a64 | 木夹颜色 |
rope | 颜色 | #6f6a62(浅色模式),#cfc6b8(深色模式) | 晾衣绳颜色 |
breeze | 0–1 | 0.45 | 风吹动布料的强度 |
weave | 0–1 | 0.5 | 近距离下平纹织法的可见程度 |
poke | 0–1 | 1 | 指针下凹陷的深度;0 关闭此效果 |
drag | true / false | true | 允许访问者抓取并拖拽布料 |
size | 0.6–1 | 0.76 | 布料在文案旁所占空间的比例(留出拖拽空间) |
hint | 40 字符 | “按一按 · 拉一拉 · 放开手” | 宽屏上远底角的小提示,告诉访问者可以触摸;" · " 分隔各部分;空字符串表示无 |
写作建议:页面上的标题和布料上的大字应表达不同内容;布料看起来像一张海报,因此文字应少而大。两个或三个规格对比六个更易读。如果品牌有关于轻盈、飞翔、晾晒或悬挂的有趣口号,布料是放置它的好地方。
3. 构建
node <skill>/scripts/build.mjs hero.json out
它会一次性列出 hero.json 中的所有问题(缺失字段、文本超限、设置超出范围、颜色对比度不足、印刷内容在布料上颜色过浅等),并在修复前不会写入任何内容。然后它会打印所使用的设置以及需要注意的问题,例如为了标题在 4.5:1 对比度下可读而调暗的强调色。
它会写入 out/index.html(CSS、脚本、Logo 和静态图片全部内联)、out/embed.html 和 out/assets/logo.svg(标签页图标)。
4. 检查
node <skill>/scripts/check.mjs out/index.html
它会在 390、768、1024 和 1440 像素宽度下加载页面,并且必须在每个宽度下输出 ok:没有内容超出屏幕或被截断,每行文本与背景天空的对比度可读,每个链接和按钮都有名称,仅有一个 h1。标记为 · 的行需要注意但不视为失败。
5. 查看并触摸它
node <skill>/scripts/record.mjs out/index.html --still 1.6 --size 1440x900
node <skill>/scripts/record.mjs out/index.html --still 3.5 --size 1440x900
node <skill>/scripts/record.mjs out/index.html --still 1.6 --size 390x844 --scale 2
node <skill>/scripts/screenshot.mjs out/index.html
第一张是布料静止状态,第二张是拖拽中(脚本手抬起一角),第三张是手机视图。检查它们:整块布料是否在屏幕内并有足够空间,印刷内容是否可读,木夹是否在绳上?screenshot.mjs 在无 GPU 的 Chrome 中运行,因此展示的是访问者在没有 WebGL 或网络故障时看到的静态图片(位于 out/screens/);检查它是否也可读。
然后在浏览器中打开 out/index.html 进行交互:悬停、按压、将一角拉过晾衣绳、松手。在手机上,用手指拖拽并检查在布料旁滑动时页面是否仍可滚动。
6. 录制视频
node <skill>/scripts/record.mjs out/index.html --seconds 10
它会以 30 fps、1920×1080 分辨率步进英雄区 10 秒,并写入 out/preview.mp4 和 out/poster.png(第 3.5 秒的帧,拖拽中)。视频中,一个绘制的手指针在 2.2 秒时抓住右下角,向上拉向你,在 4.4 秒时松手,然后从 6 秒开始用指尖掠过布料表面。选项:--size 1080x1350(竖屏)、--size 1080x1920、--fps 60、--poster 1.6。只要录制从 0 开始(它始终如此),帧内容在任何机器上都是一致的。
7. 上线发布
- 作为页面:将
out/index.html和out/assets/上传到任意静态托管服务(Cloudflare Pages、Netlify、Vercel、GitHub Pages、S3)。使用out/poster.png(或其 1200×630 裁剪版)作为meta.image,与网站一同上传。 - 嵌入已有网站:将
out/embed.html粘贴到英雄区所在位置。所有内容都限定在#mh-washing-line作用域下;如有需要,可将字体<link>移到<head>中。如果网站已有<script type="importmap">,请将嵌入的imports和integrity条目合并进去。该区域默认占满视口高度;可通过设置--mh-height调整(例如style="--mh-height:760px")。在 React 或其他框架中,可将标记放入组件,将<script>标签放入页面,或通过 iframe 渲染。 - 要更改印刷内容,编辑
hero.json并重新构建。
故障排除
build: fix hero.json first:每行说明哪个字段及如何修改;颜色问题会建议一个可行的颜色。- 布料在边缘被裁剪:降低
size,或使布料更方形(aspect接近 1)。 - 布料上的大字太小:它们会缩放以适配规格列。使用更少的词语、一个
\n、更少的规格或关闭图标(此时文字将占满宽度)。 - 布料无法静止或抖动过大:降低
breeze。 - 凹陷太强或太弱:调整
poke(设为 0 可关闭;拖拽仍有效)。 record: the effect didn't start:页面降级为静态图片——Chrome 无法从 jsDelivr 加载 three.js(检查网络连接或代理)或没有 WebGL。ffmpeg not found:安装 ffmpeg 或设置FFMPEG_PATH。- 访问者看到静态布料:其浏览器关闭了 WebGL 或 CDN 被屏蔽(平面图片),或请求了减少动效(布料在静止状态的一帧,不会移动)。这是设计使然。
- 在手机上页面无法滚动:仅当手指握持布料时停止滚动;在布料旁滑动。如果布料占满手机屏幕,降低
size。
文件
scripts/build.mjs、scripts/record.mjs:您要运行的脚本。它们调用 Motion Heroes 工具集。scripts/kit/:所有 Motion Heroes 技能共享的工具集:构建与检查(build.mjs)、区域 CSS(shell.css)、浏览器运行时(runtime.js:时钟、暂停、像素比、减少动效、降级)、录制器(record.mjs、cdp.mjs)、固定版本的 three.js 和字体(three.json、fonts.json)以及KIT.md(相关说明)。scripts/effect/:晾衣绳本身:effect.mjs(设置、检查和静态图片)、effect.js(天空着色器、……
……[为翻译已截断]