关于 shaders-cursor-ripples
这是一项编码技能,用于在保留页面内容的同时,为现有图像添加 Shaders 的 CursorRipples 效果,并提供无障碍回退。
主要功能
- 01按框架选择 Shaders 导入路径
- 02由光标驱动的图像扭曲
- 03检查 WebGPU 和动态偏好
- 04延迟加载着色器并保留回退
- 05图层组织与验证指南
适用场景
- 01为现有图像添加波纹效果
- 02替换自定义聚光灯揭示效果
- 03在不支持 WebGPU 时保留媒体可用性
- 04检查减少动态效果与指针行为
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ mengto/ skills --skill shaders-cursor-ripples安装后在 Claude Code 中输入/shaders-cursor-ripples确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
REFERENCES.mdagents/openai.yamlassets/react/cursor-ripple-media.csscursor-ripple-shader.tsx详细介绍
Shaders Cursor Ripples
核心约定
- 保留现有页面、内容和语义图像。
- 安装
shaders,并从当前框架的子路径导入。 - 通过一个
Shadercanvas 渲染源图像。 - 将
CursorRipples放在ImageTexture后面,以便对该图像进行后处理。 - 在根节点上保留
toneMapping="aces"。 - 让 Shaders 跟踪光标。移除自定义聚光坐标、径向遮罩、重复的显露图像和指针动画循环。
- 在 canvas 下方保留一张真实图像,作为无障碍加载和 WebGPU 回退。
- 在减少动态效果或不支持 WebGPU 时禁用着色器。
- 延迟加载着色器代码,避免库增大初始页面包。
如果用户只要求着色器效果,不要照搬参考中的飘带、团块、辉光、排版、布局、文案、颜色或视觉标识。不要用 Shaders 的 Water 组件替代:CursorRipples 是交互式图像位移效果。
编辑前检查
- 找到真实的媒体包装器、图像 URL、裁剪方式、叠加层、z-index 和现有动态效果。
- 确认包装器具有非零的实际渲染宽度和高度。
- 搜索旧的显露代码,例如
data-reveal-hover、mask-image: radial-gradient、重复图像、requestAnimationFrame和手动指针监听器。 - 保留无关的视差或入场动态效果,除非它们与着色器 canvas 冲突。
- 如果
shaders包可能已更新,请检查已安装的版本和当前框架 API。
安装
npm install shaders
从 shaders/react、shaders/vue、shaders/svelte 或 shaders/solid 导入。对于 Vite 项目,切勿将 shaders 添加到 optimizeDeps.exclude;它的 CommonJS 依赖需要由 Vite 预打包。通常无需配置 optimizeDeps。
在商业发布前,请核实 Shaders 当前的许可条款。
必需的组合方式
保留以下组件顺序和值:
<Shader toneMapping="aces">
<ImageTexture url={imageUrl} objectFit="cover" />
<CursorRipples decay={7.3} radius={0.6} />
</Shader>
以此为基准,然后再调整 intensity、chromaticSplit 或 edges。除非用户明确要求参考中的生成式艺术作品,否则不要添加 SolidColor、Blob、Form3D、GaborNoise、Glow 或其他生成器。
对于 React,请复制并调整 assets/react/cursor-ripple-shader.tsx 和 assets/react/cursor-ripple-media.css。
客户端与回退模式
仅当浏览器确认支持 WebGPU 且允许动态效果时,才挂载着色器:
const CursorRippleShader = lazy(() => import("./cursor-ripple-shader"));
const [shaderEnabled, setShaderEnabled] = useState(false);
const [shaderReady, setShaderReady] = useState(false);
useEffect(() => {
const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)");
const sync = () => {
const enabled = "gpu" in navigator && !reduceMotion.matches;
setShaderEnabled(enabled);
if (!enabled) setShaderReady(false);
};
sync();
reduceMotion.addEventListener("change", sync);
return () => reduceMotion.removeEventListener("change", sync);
}, []);
在包装器中保留语义图像,然后叠加延迟加载的着色器:
<figure className="cursor-ripple-media">
<img
className="cursor-ripple-media__fallback"
src={imageUrl}
alt={meaningfulAlt}
width={width}
height={height}
/>
{shaderEnabled ? (
<Suspense fallback={null}>
<CursorRippleShader
imageUrl={imageUrl}
ready={shaderReady}
onReady={() => setShaderReady(true)}
/>
</Suspense>
) : null}
</figure>
对于 Next.js,也可以使用 ssr: false 的动态导入。不要在着色器调用 onReady 前隐藏回退内容;如果 WebGPU 初始化失败,页面仍必须清晰可读且内容完整。
分层规则
- 为媒体包装器设置
position: relative、明确的尺寸、overflow: hidden和isolation: isolate。 - 将回退内容的 z-index 设为
0,将 canvas 的 z-index 设为1。 - 使用
position: absolute; inset: 0; width: 100%; height: 100%填满包装器。 - 为着色器图层设置
pointer-events: none;Shaders 会全局监听指针,并使用 canvas 边界转换指针坐标。 - 将着色器包装器标记为
aria-hidden="true";由回退图像提供无障碍名称。 - 将文案、链接和控件放在 canvas 上方,确保效果不会拦截交互。
- 确保回退内容与
ImageTexture使用相同的裁剪方式。对于满幅媒体,请使用objectFit="cover"。
移除失效的聚光灯模式
删除旧实现,不要将其隐藏:
- 第二张揭示图片;
- 径向
mask-image和自定义揭示变量; - 与指针位置相关的烟雾或模糊叠加层;
- 组件本地的
requestAnimationFrame指针缓动; - 仅为手电筒效果添加的
pointerenter、pointermove、pointerleave和尺寸调整记录逻辑; - 引用已弃用揭示层的粗略指针规则。
同时保留两套系统会导致坐标漂移、增加 GPU 负载,并使回退行为变得混乱。
性能与动态效果
- 仅在 WebGPU 检查通过后,延迟加载着色器模块。
- 媒体面板中只保留一个着色器画布。
- 使用库的
onReady回调实现短暂的不透明度切换。 - 不需要遥测时使用
disableTelemetry。 - 不要为画布尺寸添加动画;如需视差效果,应为稳定的父级元素添加动画。
- 在
prefers-reduced-motion: reduce时禁用或卸载着色器。 - 确保触控布局在使用静态图片时仍可用;不要将关键信息放在效果内部。
验证
运行项目的 lint、生产构建、渲染测试和 git diff --check。然后在真实浏览器中验证:
- 确认恰好存在一个
canvas[data-renderer="shaders"]。 - 确认着色器进入就绪类,且回退图片仍然存在。
- 在媒体区域的多个位置扫动指针。扭曲效果必须沿指针路径移动,不得出现脱离的圆圈。
- 确认链接和控件仍可点击。
- 确认没有控制台错误或警告。
- 确认 WebGPU 不可用或启用减少动态效果时,静态图片仍然显示。
- 确认旧的
data-reveal-hover或径向遮罩层不存在。 - 画布初始化后,检查移动端和桌面端的裁切效果。
故障诊断
- **画布存在但内容空白:**确认包装元素的尺寸非零,且图片 URL 同源或可通过 CORS 读取。
- **图片已渲染但没有波纹:**将
CursorRipples保留在ImageTexture之后;它需要子元素/输入表面。 - **波纹位置偏移:**移除手动指针变换,并检查经过变换的祖先元素是否改变了画布边界。
- **页面在 SSR 期间崩溃:**将着色器移入仅客户端运行的延迟加载组件。
- **图片加载时闪烁:**保留回退图片,并且仅通过
onReady淡入着色器。 - **初始包体积变大:**确认 Shaders 导入仅位于延迟加载模块中。
- **效果挡住按钮:**确保画布对指针事件透明,并将控件放在更高的堆叠层级。
交接
报告受影响的媒体、Shaders 包版本、回退行为、减少动态效果时的行为、构建/测试结果,以及实时交互验证情况。明确区分本地已就绪的效果与已发布的部署。