Community编程与开发github.com

WebGL 波浪表单

用 Three.js r178 构建 Stripe 风格的英雄区波浪:模仿 stripe.com 的折叠纸张(对折、厚实、圆边),使用 Stripe 的非光照着色(沿纸张绘制的调色板、长丝滑条纹、淡色底面),大尺寸且被画框裁剪,每个部分随自身噪声漂移。

WebGL 波浪表单 是什么?

该技能专门用于响应开发者或AI代理请求,创建类似 Stripe 官网的 3D 波浪视觉元素。它的核心是一张对折的 400x400 平面,带有圆边,通过顶点着色器中的 UV 驱动折叠、扭曲和噪声波动,实现标志性的“折叠纸张”效果。技能严格遵循 Stripe 的设计原则:使用非光照着色(Unlit Shading)和定制调色板(沿长度渐变,边缘泛白),并包含旋转模糊和静态抖动(dither)的后处理通道。支持五种预设波浪(wave、deep、fold、petal、turn),每种都有精确的扭曲、噪声、相机和发光参数。用户输入必须是意义(如“所有模型通过一个端点”),而非形状(如“龙卷风”),系统会将这些意义映射到波浪的预设和着色设置上,而非创建新几何体。技能提供了完整的工作流程,包括与真实 Stripe 网站的截图对比、性能降级策略、以及确保文字在波浪上可读的双层复制技术。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/Rahuchpred/raha/tree/main/skills/webgl-form

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

WebGL 形式

形式就是波浪:stripe.com 的折叠纸张,正如 stripe.com 所绘制的那样。 用户在多次尝试后的评价是:“我只喜欢波浪,因为它确实是一个好的形式。波浪正是我想要的。” 所有尝试过的其他形式(环、结、弹簧、螺旋漏斗、缠绕的纸张)都被拒绝了。因此,一个想法永远不会变成一个新的形状。它会变成一个带有自己颜色、裁剪和设置的波浪。

文件说明
reference/stripe-three.js核心引擎。 Three.js r178:在顶点着色器内构建的折叠纸张,Stripe 的扭曲作为旋转列表,Stripe 的非光照着色,绘制的调色板,后处理通道,以及五个可用波浪的 TAKES / PRESETS。复制它,然后添加预设。
reference/stripe-notes.mdstripe.com 的英雄区波浪的正式发布状态:折叠几何体、着色器、相机以及其所有四个波浪的设置。在调整前阅读。
reference/twist-ribbon.js, reference/nib-ribbon.ts较早的纯 WebGL2 丝带(OpenRouter, OpenEvidence)。仅用于已经运行它们的项目。
reference/ReactMount.tsx带有后备方案的 React/Next 挂载组件。

0. 需要询问的内容

提示承载的是意义,而非形状。形状曾导致失败:每一个按字面构建的命名形式(莫比乌斯环、结、弹簧、龙卷风)最终都看起来像 3D 剪贴画。OpenRouter 丝带之所以有效,是因为其意义(“许多模型,一个端点输出”)变成了设置(纸张何处转向边缘),而非产品的图画。

在一次消息中最多询问三件事:

  1. 想法,用一句话概括:产品做什么,或者艺术作品要表达的唯一内容。(“每个模型通过一个端点。”)
  2. 颜色:品牌的颜色,或者“从代码中读取”(globals.css 中的标记、Tailwind 主题、Logo 的颜色)。
  3. 位置:英雄带(在文字下方或周围)、单元格、卡片;亮色或暗色页面。

完全没有提示也是一种有效用法:从代码中读取颜色,在 Stripe 的亮色英雄区位置使用 wave 预设,并用一行说明。

一个命名的形状(例如“制作一个龙卷风”):不要构建该形状。将其视为关于意义的提示(龙卷风:上升、旋转、力量),并映射到下面的设置。用一行告诉用户该技能保留波浪及其原因。如果他们仍然坚持,就构建该形状作为一个额外的选项(与波浪并列,并标注),供他们比较。

从意义到设置(起点,非规则):

想法感觉从以下开始更改
平静、信任、金钱、健康deep节奏 4e-5,冷色或暖中性调色板,宽裁剪
多归于一、焦点、端点wave将边缘拉伸(收窄处)放在文字下方或旁边
能量、实时、速度petal 或 fold节奏提升至 8e-5,暖色调色板
变化、两面、转折turn翻卷展示两面
无特定内容wave仅品牌调色板

输出: 在选项页面上提供两个或三个选项,同一波浪系列的不同预设、裁剪或调色板。用户选择一个;删除其余的。

1. 形式

  • 折叠纸张:一个 400 x 400 的平面(128 x 256 分段)对折:顶层是一个 32 单位宽的条带,弯曲成半个圆柱体(圆角折叠),底层折叠在下方,末端相距 4 个单位,中间相距 2 个单位。直立起来经过两个四分之一转:长度沿 x 轴,厚度沿 y 轴,宽度沿 z 轴。厚重,带有圆边,绝无线宽。在顶点着色器中通过 UV 构建(folded(uv)),因此法线是精确的。
  • Stripe 的三个扭曲塑造了它:围绕对角线轴 (.5, 0, .5) 和 (0, .5, .5) 的旋转,每个都通过 Stripe 的软阶梯函数 exp2(-exp2(n) * pow(x, n)) 沿宽度 (u) 或长度 (v) 进行渐变。在引擎中:使用 Stripe 的参数 stripeTwists([x, y, z], [powX, powY, powZ])。x 扭曲沿长度在噪声上漂移:这,连同噪声波,就是全部的运动。部分移动;整体从不旋转。
  • 噪声波:p.y += amount * noise(x * fx + t, z * fz + t)。
  • 在 Stripe 画框中的位置:一个 1392 像素宽的画布(像素单位),正交相机位于 (100, 0, 5000),绕 y 轴旋转 0.02 弧度;每个数字按 画布宽度 / 1392 缩放。始终大尺寸并被其画框裁剪,从不显得小而浮动。
  • 节奏:Stripe 的时钟,每毫秒 4e-5 到 8e-5。刻意缓慢。

2. 五种有效的波浪

其中四个是 stripe.com 发布的波浪,带有其精确设置(扭曲 x, y, z;幂次;噪声波;位置;发光;节奏)。第五个增加了一个旋转。

预设来源扭曲 x, y, z / 幂次噪声波旋转;缩放;位置发光节奏,偏移
waveStripe 亮色英雄区-0.65, 0.41, -0.58 / 3.63, 0.7, 3.950.005831, 0.016001, -7.821-0.4496, -0.1176, 1.8744; 9, 8, 5; 380, -301.7, -11.11.98, 0.806, 0.8344e-5, 17500
deepStripe 暗色英雄区,在白色上绘制-0.055, 0.077, -0.518 / 3.95, 5.85, 6.330.003234, 0.00799, 6.051-0.1596, -0.2836, -2.8156; 10, 10, 7; -24.3, -56.4, -11.10.6, 0.589, 14e-5, 1150
foldStripe 结算英雄区,调整为适配单元格-0.424, 0.024, -1.312 / 1.81, 0.94, 4.760.005, 0.0212, 6.68-0.666, -0.0314, 1.9; 6.05, 8.4, 6.99; 50, -100, -11.11.55, 1.174, 0.9725.25e-5, 17500
petalStripe 小型强调波浪,放大并旋转0.059, 0.32, -0.397 / 3.63, 0.44, 5.990.005831, 0.016001, -7.821-2.8756, 3.0959, -1.6; 9, 9, 9; 0, -50, -11.13.86, 0.923, 18e-5, 2275
turn亮色英雄区,完全翻转(唯一有效的额外旋转)亮色英雄区的,加上 沿 v 方向长度 (1, 0, 0),2pi,漂移 0.15亮色英雄区的亮色英雄区的亮色英雄区的亮色英雄区的

粗体数字与 Stripe 自己的位置不同:Stripe 为它自己的画框放置了这些波浪,因此在一个更小的单元格中,它们要么被裁剪成一片平坦的区域,要么显得很小。重新放置,绝不重塑:为了适配不同的画框,仅更改旋转、缩放和位置(HTML 中的 data-overrides)。

3. 着色:Stripe 自己的非光照着色

正在运行的 stripe.com 英雄区完全没有光照;这就是为什么它看起来明亮、有光泽而非塑料感。其表面是:

  1. 纸张上的调色板:在 (u, v) 坐标处。
  2. 沿长度的长而细的条纹:n0 = noise(u * 0.1, v * 0.5),n1 = noise(u * (600 + 300 n0), v * 4 n0)(横向极细,纵向几乎恒定),以 n1 * 0.2 到 0.26 * (1 - blue * 0.9) * pdy * edge 添加,其中 edge = 1 - pow(4u(1 - u), 3)(在靠近开放边缘处最强)。它们在暖色上效果最好;对于全蓝色调色板,将蓝色淡化系数降低至大约 0.4。
  3. 发光项 pdy:dFdy(v) * resolution.y * amount,从 -1..1 映射到 0..1,提升幂次,通过斜坡函数进行平滑阶梯处理。其符号指示纸张的两个面;接近零时纸张正在折叠。
  4. 对比度、饱和度、色相,然后 + (1 - pdy) * 0.25:另一面以及折叠处变淡。这就是 Stripe 折叠处那奶油色的带子。
  5. 不透明,深度测试。后处理通道:一个 0.02 弧度的旋转模糊,保持在画面中部的一个锐利条带之外,然后在有颜色的区域添加颗粒(1.1)。颗粒是 Stripe 的静态抖动:color + mix(1, -1, random( gl_FragCoord.xy * 0.01)) * 4/255 * amount。它从不逐帧变化。每帧都重新随机化的颗粒会闪烁并被视为噪声(“与 Stripe 相比噪声太多”),并且在视频中还会使文件大小增加数倍。

没有绘制的线条,没有运动的光线,没有法线光照,没有折痕高光:引擎中较旧的有光照着色仅作为选项保留(shading: "lit"),并且不是默认设置。

4. 调色板

按照 Stripe 运行的方式绘制它,而不是随机色块(随机色块在纸张的大部分可见区域产生了一种平坦的颜色):

  • 沿长度 (v),主渐变。亮色英雄区:薰衣草蓝 #9fb6ff,紫罗兰 #a978ff,品红 #e05cff,热粉色 #ff4fa8,橙色 #ff7a2a,琥珀色 #ffa318。
  • 沿宽度 (u),朝向开放边缘的色调(大约 75%,从每侧 u = 0.22 处逐渐消失):亮色英雄区为薰衣草色 #a9b6ff。
  • 一些微弱的色块(14 个,强度 25%),仅用于增加变化。
  • 引擎的 palette(along, edge, blobs) 构建了这个。其他可用的组合:海洋(蓝到青),黄昏(橙、粉、紫),青柠(青、绿、黄、橙),余烬(粉、红、橙、黄)。
  • 颜色是品牌的,或类似 Stripe 的风格。装饰性的,绝非数据。

5. 在页面中的位置

文字叠加在波浪上(Stripe 的重叠方式)

于 2026-10-22 在 stripe.com 上测量。当波浪在标题下方运行时,Stripe 不会将其遮罩掉,也不会让波浪覆盖文字。它会两次绘制文字:

  1. 在画布下方:文字使用其正常颜色(Stripe:标题海军蓝 #061b31,正文灰色)。当波浪经过它时,波浪将其隐藏。
  2. 在画布上方(z-index 高于波浪层):一个完全相同的文字副本,相同的大小和位置,aria-hidden,带有 mix-blend-mode: hard-light 和半透明的着色颜色(Stripe:标题 rgb(45, 37, 100),深紫色;正文 rgba(0, 14, 255, 0.5),半透明蓝色)。在白色页面上,它看起来像普通文字;在波浪上,字母会呈现波浪的颜色,因此它们保持可读,看起来像是印在丝绸上。

规则:

  • 从品牌中选择顶部文字副本的色调:标题颜色的一种深邃、高饱和版本,以及半透明的品牌蓝色(或强调色)用于正文。检查一张波浪最亮时的截图:每个单词仍然可读。

  • 两个文字副本必须完全匹配(相同的元素样式,相同的换行):从一个源构建它们,并在一个网格单元格中堆叠(grid-area: 1 / 1),这样字体或宽度的更改会同时影响两者。

  • 屏幕阅读器只获取下方的文字副本;上方的副本是 aria-hidden 且不接收指针事件。按钮和链接保持在底层,绝不被画布覆盖(将它们保持在波浪路径之外,或仅将按钮提升到其上方)。

  • 减少动画模式和静态图像后备方案保留两个副本;混合模式在静态图像上也能正常工作。

  • 绝不让文字使用白色面板或遮罩来避开波浪:这正是双层文字副本旨在避免的外观。

  • 波浪填充或裁剪其单元格或英雄带。说明文字位于一个小的页面颜色芯片上。

  • 绝不能进入导航栏或下一节。当裁剪后的波浪遇到带子的顶部时,使用 CSS 遮罩使其淡出;当遇到文字时,使用上面的双层文字副本。

  • 艺术作品内部没有标签、数字或网格线。

6. 工程规则

  • Three.js r178 已安装到项目中,使用 import map 加载("three": "/node_modules/three/build/three.module.js")。
  • THREE.ColorManagement.enabled = false;调色板 NoColorSpace;ShaderMaterial 使用 GLSL1 风格。
  • failIfMajorPerformanceCaveat: true;失败时显示同一波浪的静态图像。监控帧时间:先放弃后处理通道,然后降低 DPR,最后停止在静止帧上。
  • DPR 上限为 2;使用 ResizeObserver;在屏幕外和隐藏标签页中暂停;减少动画模式绘制一个静止帧。无指针交互。
  • 页面上最多大约 13 个波浪;超过 16 个时浏览器会丢失上下文。
  • 绝不要将 GLSL 变量命名为 step、mix 或 fract。

7. 工作流程

  1. 获取输入(第 0 节):想法、颜色、位置。无提示:颜色从代码中获取,使用 wave 预设。将想法映射到预设、裁剪和调色板;绝不映射到新形状。
  2. 与真实事物对比:截取 stripe.com 英雄区在 1440x900 下的屏幕截图,在 Stripe 的精确画框(1392 x 761,位于 x 337)中渲染我们的版本,并在相同裁剪下比较两者。纹理和颜色以这种方式判断,而非凭记忆。
  3. 对于包含多个波浪的页面,使用上面的预设,重新放置以适配每个画框;在选项页面上展示备选方案。
  4. 全尺寸验证(无头 Chrome):控制台干净,每个画布都构建成功;验证 1440 和 375 宽度;比较相隔四秒的两帧的每个四分之一区域(不均匀变化:部分在移动;均匀变化:旋转);波浪填满其画框。
  5. 提交时附带一条消息,说明视觉上改变了什么。

已被拒绝,请勿重复

  • 按字面理解一个命名的形状。 像“制作一个龙卷风”这样的提示是关于意义的提示,而非几何体。
  • 任何波浪以外的形式。 环、结、弹簧和沿路径扫掠的管状物(“其他那些看起来并不真正酷”),以及通过强劲扭曲推入其他形状的折叠纸张:螺旋漏斗、缠绕的线圈、纠缠(“纠缠、线圈和漏斗都非常糟糕”)。只有温和的翻转(turn)通过了,被评价为“也许还行”。
  • 有光照、有阴影的纸张:它们靠近 Stripe 的非光照表面时会显得像塑料。
  • 随机色块调色板:会导致纸张可见区域填满一种平坦的颜色。
  • 单层纸张:“你可以看到薄薄的侧边”。
  • 整个物体旋转:“整个东西在动,而不是某些部分”。
  • 移动的光线:“那只是 OpenRouter 的东西,这里我们模仿 Stripe”。
  • 画框中间浮动的小波浪。
  • 在任何透明物体上使用普通 Alpha 混合:会产生接缝。
  • 在艺术作品内绘制线条、节点-连线图、网格线、标签或计数;波浪延伸到导航栏下方。

相关技能