关于 web-cloud-designer
面向网页开发者的云朵视觉设计技能,介绍使用 SVG 滤镜、CSS 动画和分层效果创建云景。内容兼顾视觉类型、视差与性能优化,适用于背景、天气界面和加载状态。
主要功能
- 01使用 SVG 滤镜生成云朵形态
- 02分层构建景深与视差
- 03通过 CSS 动画呈现云层移动
- 04提供 React 和 Vue 实现模板
- 05优化滤镜与动画性能
- 06支持减少动态效果偏好
适用场景
- 01制作带云景的网页主视觉背景
- 02设计天气主题界面和转场
- 03创建视差云层场景
- 04为加载状态添加云朵动画
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ curiositech/ some_claude_skills --skill web-cloud-designer安装后在 Claude Code 中输入/web-cloud-designer确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.md.claude-plugin/plugin.jsonreferences/animation-patterns.mdsvg-filter-deep-dive.mdcolor-and-lighting.md详细介绍
Web Cloud Designer
擅长使用 SVG 滤镜、CSS 动画和分层技术,为 Web 应用创建逼真且高性能的云效果。专注于提升用户体验且不牺牲性能的氛围视觉效果。
适用场景
适用于:
- 逼真的云背景和天空盒
- 天气主题的 UI 元素和过渡效果
- 有纵深感的视差云景
- 动态氛围效果
- 风格化/卡通风格的云朵设计
- 天空主题的首屏背景
- 带云朵动画的加载状态
- 游戏风格的云层
不适用于:
- 3D 体积云渲染 -> 使用 WebGL/Three.js
- 真实云朵的照片处理 -> 使用图像编辑工具
- 天气数据集成 -> 使用天气 API 技能
- 不含云朵形状的简单渐变天空
- 云朵视频背景
核心技术参考
SVG 滤镜管线
基础云效果使用以下滤镜链:
Source -> feTurbulence -> feDisplacementMap -> feGaussianBlur -> feDiffuseLighting -> Composite
1. feTurbulence - 基础
生成构成云朵形状的 Perlin 噪声。
<feTurbulence
type="fractalNoise"
baseFrequency="0.01"
numOctaves="4"
seed="42"
result="noise"
/>
| 参数 | 范围 | 效果 |
|---|---|---|
baseFrequency | 0.005-0.02 | 云朵形状的大小。0.005 = 巨型积云,0.02 = 细小的云丝 |
numOctaves | 3-5 | 细节层数。3 = 平滑,5 = 细节丰富。超过 5 = 浪费 CPU |
seed | 0-999999 | 形状变化。想要变化时修改此项,而非 baseFrequency |
type | fractalNoise | 云朵始终使用 fractalNoise(turbulence = 火焰/水流) |
2. feDisplacementMap - 形状扭曲
用噪声创建自然、有蓬松感的云朵形状。
<feDisplacementMap
in="SourceGraphic"
in2="noise"
scale="80"
xChannelSelector="R"
yChannelSelector="G"
/>
| Scale 值 | 效果 |
|---|---|
| 20-50 | 细微、飘逸的卷云 |
| 50-100 | 均衡的积云 |
| 100-170 | 戏剧性、翻涌的风暴云 |
3. feGaussianBlur - 边缘柔化
重要:为提升性能,需在位移前应用(根据 CSS-Tricks)。
<feGaussianBlur
stdDeviation="3"
result="blurred"
/>
4. feDiffuseLighting - 体积感
为平面噪声添加类似 3D 的阴影效果。
<feDiffuseLighting
in="noise"
lighting-color="white"
surfaceScale="2"
result="light"
>
<feDistantLight
azimuth="45"
elevation="55"
/>
</feDiffuseLighting>
云朵类型配方
积云(蓬松、明快的云朵)
<svg width="100%" height="100%">
<defs>
<filter id="cumulus" x="-50%" y="-50%" width="200%" height="200%">
<feTurbulence type="fractalNoise" baseFrequency="0.008"
numOctaves="4" seed="5" result="noise"/>
<feGaussianBlur in="noise" stdDeviation="4" result="blur"/>
<feDisplacementMap in="SourceGraphic" in2="blur" scale="60"/>
</filter>
</defs>
<ellipse cx="200" cy="100" rx="150" ry="80"
fill="white" filter="url(#cumulus)"/>
</svg>
卷云(纤细、高空云)
<filter id="cirrus">
<feTurbulence type="fractalNoise" baseFrequency="0.02 0.005"
numOctaves="3" seed="12" result="noise"/>
<feGaussianBlur in="noise" stdDeviation="2" result="blur"/>
<feDisplacementMap in="SourceGraphic" in2="blur" scale="25"/>
</filter>
要点:使用各向异性的 baseFrequency(两个值),生成拉伸且有方向性的细长云丝。
层云(平坦云层)
<filter id="stratus">
<feTurbulence type="fractalNoise" baseFrequency="0.015 0.003"
numOctaves="3" seed="8" result="noise"/>
<feGaussianBlur stdDeviation="6" result="blur"/>
<feDisplacementMap in="SourceGraphic" in2="blur" scale="30"/>
</filter>
积雨云(风暴云)
<filter id="storm">
<feTurbulence type="fractalNoise" baseFrequency="0.006"
numOctaves="5" seed="99" result="noise"/>
<feGaussianBlur in="noise" stdDeviation="3" result="blur"/>
<feDisplacementMap in="SourceGraphic" in2="blur" scale="150"/>
<feDiffuseLighting in="blur" lighting-color="#8899aa" surfaceScale="3">
<feDistantLight azimuth="230" elevation="25"/>
</feDiffuseLighting>
</filter>
风格化/卡通云朵
<filter id="cartoon">
<feTurbulence type="fractalNoise" baseFrequency="0.012"
numOctaves="2" seed="3" result="noise"/>
<feDisplacementMap in="SourceGraphic" in2="noise" scale="40"/>
</filter>
分层策略
使用多个云层营造纵深感:
<div class="sky">
<div class="clouds clouds-back"></div>
<div class="clouds clouds-mid"></div>
<div class="clouds clouds-front"></div>
</div>
.clouds-back {
filter: url(#cloud-soft);
opacity: 0.3;
animation: drift 120s linear infinite;
transform: scale(1.5);
}
.clouds-mid {
filter: url(#cloud-medium);
opacity: 0.6;
animation: drift 80s linear infinite;
transform: scale(1);
}
.clouds-front {
filter: url(#cloud-sharp);
opacity: 0.9;
animation: drift 50s linear infinite;
transform: scale(0.8);
}
图层参数指南
| 图层 | 不透明度 | 速度 | 缩放 | blur stdDeviation |
|---|---|---|---|---|
| 后景(远处) | 0.2-0.4 | 90-120s | 1.3-1.5x | 5-8 |
| 中景 | 0.5-0.7 | 50-80s | 1.0x | 3-5 |
| 前景(近处) | 0.8-1.0 | 30-50s | 0.7-0.9x | 1-3 |
动画技术
CSS 关键帧(推荐 - 性能最佳)
@keyframes drift {
from { transform: translateX(-100%); }
to { transform: translateX(100%); }
}
@keyframes morph {
0%, 100% { border-radius: 60% 40% 30% 70% / 60% 30% 70% 40%; }
50% { border-radius: 30% 60% 70% 40% / 50% 60% 30% 60%; }
}
.cloud {
animation:
drift 60s linear infinite,
morph 15s ease-in-out infinite;
}
SVG Animate(谨慎使用 - CPU 占用高)
<feTurbulence baseFrequency="0.01" numOctaves="4">
<animate
attributeName="baseFrequency"
values="0.008;0.012;0.008"
dur="20s"
repeatCount="indefinite"
/>
</feTurbulence>
警告:动画化滤镜属性会重新计算整个滤镜。仅用于首屏特效,不要用于背景循环动画。
GSAP(控制力最佳)
gsap.to("#cloud-filter feTurbulence", {
attr: { baseFrequency: 0.015 },
duration: 10,
ease: "sine.inOut",
yoyo: true,
repeat: -1
});
3D 视差(广告牌技术)
.cloud-layer {
transform-style: preserve-3d;
perspective: 1000px;
}
.cloud {
transform: translateZ(-100px) scale(1.1);
/* Further clouds appear smaller, move slower on scroll */
}
完整实现模板
模板 1:简单天空背景
<!DOCTYPE html>
<html>
<head>
<style>
.sky {
position: relative;
width: 100%;
height: 100vh;
background: linear-gradient(180deg, #87CEEB 0%, #E0F6FF 100%);
overflow: hidden;
}
.cloud {
position: absolute;
background: white;
border-radius: 50%;
filter: url(#cloudFilter);
animation: float linear infinite;
}
.cloud-1 { width: 300px; height: 150px; top: 10%; animation-duration: 80s; }
.cloud-2 { width: 400px; height: 180px; top: 30%; animation-duration: 100s; animation-delay: -30s; }
.cloud-3 { width: 250px; height: 120px; top: 50%; animation-duration: 70s; animation-delay: -50s; }
@keyframes float {
from { transform: translateX(-120%); }
to { transform: translateX(120vw); }
}
</style>
</head>
<body>
<svg style="position:absolute;width:0;height:0">
<defs>
<filter id="cloudFilter" x="-50%" y="-50%" width="200%" height="200%">
<feTurbulence type="fractalNoise" baseFrequency="0.01" numOctaves="4" seed="5"/>
<feGaussianBlur stdDeviation="4"/>
<feDisplacementMap in="SourceGraphic" scale="50"/>
</filter>
</defs>
</svg>
<div class="sky">
<div class="cloud cloud-1"></div>
<div class="cloud cloud-2"></div>
<div class="cloud cloud-3"></div>
</div>
</body>
</html>
模板 2:分层视差云朵
<style>
.parallax-sky {
position: relative;
height: 100vh;
background: linear-gradient(to bottom,
#1e3c72 0%,
#2a5298 30%,
#f5af19 90%,
#f12711 100%
);
overflow: hidden;
}
.cloud-layer {
position: absolute;
width: 200%;
height: 100%;
background-repeat: repeat-x;
}
.layer-back {
opacity: 0.3;
filter: url(#cloudBack) blur(2px);
animation: scroll 120s linear infinite;
}
.layer-mid {
opacity: 0.5;
filter: url(#cloudMid);
animation: scroll 80s linear infinite;
}
.layer-front {
opacity: 0.8;
filter: url(#cloudFront);
animation: scroll 45s linear infinite;
}
@keyframes scroll {
from { transform: translateX(0); }
to { transform: translateX(-50%); }
}
</style>
<svg style="display:none">
<defs>
<filter id="cloudBack">
<feTurbulence type="fractalNoise" baseFrequency="0.005" numOctaves="3" seed="1"/>
<feDisplacementMap in="SourceGraphic" scale="40"/>
</filter>
<filter id="cloudMid">
<feTurbulence type="fractalNoise" baseFrequency="0.008" numOctaves="4" seed="2"/>
<feDisplacementMap in="SourceGraphic" scale="60"/>
</filter>
<filter id="cloudFront">
<feTurbulence type="fractalNoise" baseFrequency="0.012" numOctaves="4" seed="3"/>
<feDisplacementMap in="SourceGraphic" scale="80"/>
</filter>
</defs>
</svg>
模板 3:React 组件
import React, { useMemo } from 'react';
interface CloudProps {
type?: 'cumulus' | 'cirrus' | 'stratus' | 'storm';
seed?: number;
className?: string;
}
const CLOUD_CONFIGS = {
cumulus: { baseFrequency: '0.008', numOctaves: 4, scale: 60, blur: 4 },
cirrus: { baseFrequency: '0.02 0.005', numOctaves: 3, scale: 25, blur: 2 },
stratus: { baseFrequency: '0.015 0.003', numOctaves: 3, scale: 30, blur: 6 },
storm: { baseFrequency: '0.006', numOctaves: 5, scale: 150, blur: 3 },
};
export const Cloud: React.FC<CloudProps> = ({
type = 'cumulus',
seed = Math.floor(Math.random() * 1000),
className
}) => {
const filterId = useMemo(() => `cloud-${type}-${seed}`, [type, seed]);
const config = CLOUD_CONFIGS[type];
return (
<>
<svg style={{ position: 'absolute', width: 0, height: 0 }}>
<defs>
<filter id={filterId} x="-50%" y="-50%" width="200%" height="200%">
<feTurbulence
type="fractalNoise"
baseFrequency={config.baseFrequency}
numOctaves={config.numOctaves}
seed={seed}
result="noise"
/>
<feGaussianBlur in="noise" stdDeviation={config.blur} result="blur"/>
<feDisplacementMap in="SourceGraphic" in2="blur" scale={config.scale}/>
</filter>
</defs>
</svg>
<div
className={className}
style={{ filter: `url(#${filterId})` }}
/>
</>
);
};
// Usage:
// <Cloud type="cumulus" seed={42} className="cloud-shape" />
模板 4:纯 CSS 盒阴影云朵
无需 SVG 滤镜,创建更简单、性能更好的云朵:
.cloud-simple {
width: 200px;
height: 60px;
background: white;
border-radius: 100px;
position: relative;
box-shadow:
/* Main body shadows for volume */
inset -10px -10px 30px rgba(0,0,0,0.05),
inset 10px 10px 30px rgba(255,255,255,0.8),
/* Outer glow */
0 10px 40px rgba(0,0,0,0.1);
}
.cloud-simple::before,
.cloud-simple::after {
content: '';
position: absolute;
background: white;
border-radius: 50%;
}
.cloud-simple::before {
width: 100px;
height: 100px;
top: -50px;
left: 30px;
}
.cloud-simple::after {
width: 70px;
height: 70px;
top: -30px;
left: 100px;
}
性能优化
关键规则
- numOctaves 不超过 5 - 超过 5 后,视觉收益递减,而 CPU 开销呈指数级增长
- 先模糊,再位移 - 比位移后再模糊高效 40%
- 避免动画化滤镜属性 - 改用 CSS transforms
- 使用
seed产生变化 - 相较于修改 baseFrequency,可免费获得变化效果 will-change: transform- 仅用于动画元素,静止时移除- 批量定义滤镜 - 使用一个
<defs>块,并通过 ID 引用
性能等级
| 等级 | 技术 | FPS 目标 | 使用场景 |
|---|---|---|---|
| 超高 | 仅使用 CSS box-shadow | 60fps | 移动设备、低端设备 |
| 高 | SVG filter,不使用动画 | 60fps | 静态背景 |
| 中 | SVG filter + CSS transform 动画 | 45-60fps | 轻微移动效果 |
| 低 | SVG filter + <animate> | 30fps | 仅适用于首屏区域 |
移动设备注意事项
@media (prefers-reduced-motion: reduce) {
.cloud {
animation: none;
}
}
@media (max-width: 768px) {
.cloud-layer {
/* Reduce to 2 layers on mobile */
}
.cloud {
filter: url(#cloudSimple); /* Fewer octaves */
}
}
性能检测
// Detect if device can handle filter animations
const canHandleFilters = () => {
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl');
if (!gl) return false;
const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');
const renderer = debugInfo
? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL)
: '';
// Reduce effects on integrated graphics
return !renderer.includes('Intel');
};
框架集成
Next.js / React
// components/CloudBackground.tsx
'use client';
import { useEffect, useState } from 'react';
export function CloudBackground() {
const [reducedMotion, setReducedMotion] = useState(false);
useEffect(() => {
const mq = window.matchMedia('(prefers-reduced-motion: reduce)');
setReducedMotion(mq.matches);
mq.addEventListener('change', (e) => setReducedMotion(e.matches));
}, []);
return (
<div className="cloud-container">
{/* SVG defs in portal to document head */}
{/* Cloud layers */}
</div>
);
}
Vue 3
<template>
<div class="sky-background">
<CloudFilter />
<div
v-for="cloud in clouds"
:key="cloud.id"
class="cloud"
:style="cloud.style"
/>
</div>
</template>
<script setup>
import { computed } from 'vue';
import CloudFilter from './CloudFilter.vue';
const clouds = computed(() =>
Array.from({ length: 5 }, (_, i) => ({
id: i,
style: {
animationDuration: `${60 + i * 20}s`,
animationDelay: `${-i * 15}s`,
top: `${10 + i * 15}%`,
}
}))
);
</script>
Tailwind CSS
// tailwind.config.js
module.exports = {
theme: {
extend: {
animation: {
'cloud-drift': 'drift 80s linear infinite',
'cloud-morph': 'morph 15s ease-in-out infinite',
},
keyframes: {
drift: {
from: { transform: 'translateX(-100%)' },
to: { transform: 'translateX(100vw)' },
},
morph: {
'0%, 100%': { borderRadius: '60% 40% 30% 70% / 60% 30% 70% 40%' },
'50%': { borderRadius: '30% 60% 70% 40% / 50% 60% 30% 60%' },
},
},
},
},
};
调试技巧
可视化滤镜步骤
<filter id="debug">
<feTurbulence result="step1"/>
<feGaussianBlur in="step1" result="step2"/>
<feDisplacementMap in="SourceGraphic" in2="step2" result="step3"/>
<feTile in="step1" result="tile1"/>
<feOffset in="tile1" dx="0" dy="0"/>
</filter>
常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 云朵被裁切 | 滤镜区域太小 | 添加 x="-50%" y="-50%" width="200%" height="200%" |
| 边缘锯齿 | 缺少模糊效果 | 在置换之前添加 feGaussianBlur |
| 缺少变化 | 使用了相同的种子值 | 使用不同的 seed 值 |
| 性能问题 | 八度数过多 | 将 numOctaves 降至 3-4 |
| 动画卡顿 | 对滤镜属性做动画 | 改用 CSS transform 动画 |
参考资料
- CSS-Tricks:《使用 SVG 和 CSS 绘制逼真的云朵》
- LogRocket:《使用 SVG CSS 制作动画云生成器》
- Codrops:《使用 feTurbulence 实现 SVG 滤镜效果》
- Click to Release:《CSS 3D 云朵》(广告牌技术)
- Nephele Cloud Generator 工具
- MDN:SVG 滤镜原语文档
云朵是大自然提醒我们,即使天空也有纹理的一种方式。
评论
支持 Markdown