web-weather-creator

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Web Weather Creator

Web天气特效生成器

Master of stylized atmospheric effects using SVG filters and CSS animations. Creates clouds, waves, lightning, rain, fog, aurora borealis, god rays, lens flares, twilight skies, and ocean spray—all with a premium aesthetic that's stylized but never cheap-looking.
精通使用SVG滤镜和CSS动画实现风格化大气特效。可创建云朵、波浪、闪电、降雨、雾霭、极光、耶稣光、镜头光晕、黄昏天空和海浪喷雾等效果——所有效果均采用高品质风格化设计,绝不显得廉价。

Activation Triggers

触发关键词

Activate on: "clouds", "waves", "weather effects", "atmospheric", "lightning", "rain", "fog", "mist", "aurora", "northern lights", "god rays", "crepuscular", "lens flare", "twilight", "sunset gradient", "golden hour", "ocean spray", "beach wash", "foam", "smoke", "parallax sky", "water ripples", "animated background"
NOT for:
  • Photorealistic renders (use WebGL/Three.js)
  • Static weather icons (use icon libraries)
  • Weather data APIs (use backend services)
  • 3D volumetric effects (use Babylon.js/Three.js)

触发词: "clouds"、"waves"、"weather effects"、"atmospheric"、"lightning"、"rain"、"fog"、"mist"、"aurora"、"northern lights"、"god rays"、"crepuscular"、"lens flare"、"twilight"、"sunset gradient"、"golden hour"、"ocean spray"、"beach wash"、"foam"、"smoke"、"parallax sky"、"water ripples"、"animated background"
不适用场景:
  • 照片级写实渲染(请使用WebGL/Three.js)
  • 静态天气图标(请使用图标库)
  • 天气数据API(请使用后端服务)
  • 3D体积特效(请使用Babylon.js/Three.js)

Philosophy: Stylized, Not Cheap

设计理念:风格化而非廉价感

The goal is premium stylization—effects that feel intentional and artistic, not like stock footage or placeholder art.
目标是高品质风格化——效果需体现设计感与艺术性,而非素材库或占位图的质感。

The Three Principles

三大原则

  1. Layering Creates Depth - Multiple semi-transparent layers with parallax motion
  2. Organic Motion - Varied speeds, easing, and subtle randomization
  3. Restraint - One hero effect, subtle supporting elements
  1. 分层营造深度 - 多个半透明图层搭配视差运动
  2. 有机运动 - 多样化速度、缓动效果与细微随机化
  3. 克制设计 - 一个核心特效,搭配细微辅助元素

Quality Spectrum

品质光谱

CHEAP ──────────────────────── STYLIZED ──────────────────────── REALISTIC
CSS gradient blob         SVG filter + layered opacity        WebGL particles
Single div animation      3-5 layers with parallax            Fluid simulation
Linear easing             Cubic-bezier + varied timing        Physics engine
Target Zone: The middle—stylized enough to feel crafted, performant enough for production.

CHEAP ──────────────────────── STYLIZED ──────────────────────── REALISTIC
CSS gradient blob         SVG filter + layered opacity        WebGL particles
Single div animation      3-5 layers with parallax            Fluid simulation
Linear easing             Cubic-bezier + varied timing        Physics engine
目标区域: 中间地带——足够风格化以体现匠心,同时性能足够适配生产环境。

Clouds Floating Through Content (Z-Index Strategy)

云朵穿梭内容效果(Z轴层级策略)

The most common question: "How do I make clouds float through my content, not just behind it?"
最常见问题:"如何让云朵穿梭于内容之间,而非仅在背景层?"

The Split-Layer Solution

分层解决方案

html
<div class="atmosphere-container">
  <!-- BACK clouds (behind content) -->
  <div class="clouds clouds--back"></div>

  <!-- Content sits in the middle -->
  <main class="content">
    <div class="card">Your content here</div>
  </main>

  <!-- FRONT clouds (in front of content, but transparent) -->
  <div class="clouds clouds--front"></div>
</div>
css
.atmosphere-container {
  position: relative;
  isolation: isolate; /* Creates stacking context */
}

.clouds {
  position: absolute;
  inset: 0;
  pointer-events: none; /* CRITICAL: Let clicks through */
  filter: url(#cloud-cumulus);
}

.clouds--back {
  z-index: -1;
  opacity: 0.3;
  transform: scale(1.5);
  animation: drift 120s linear infinite;
}

.content {
  position: relative;
  z-index: 1;
}

.clouds--front {
  z-index: 2;
  opacity: 0.12; /* LOW opacity so content is readable */
  transform: scale(0.8);
  animation: drift 50s linear infinite reverse;

  /* Optional: Mask to clear space around content */
  mask-image: linear-gradient(
    to bottom,
    black 0%,
    transparent 30%,
    transparent 70%,
    black 100%
  );
}
html
<div class="atmosphere-container">
  <!-- 背景云朵(在内容后方) -->
  <div class="clouds clouds--back"></div>

  <!-- 内容位于中间层 -->
  <main class="content">
    <div class="card">Your content here</div>
  </main>

  <!-- 前景云朵(在内容前方,半透明) -->
  <div class="clouds clouds--front"></div>
</div>
css
.atmosphere-container {
  position: relative;
  isolation: isolate; /* 创建堆叠上下文 */
}

.clouds {
  position: absolute;
  inset: 0;
  pointer-events: none; /* 关键:允许点击穿透 */
  filter: url(#cloud-cumulus);
}

.clouds--back {
  z-index: -1;
  opacity: 0.3;
  transform: scale(1.5);
  animation: drift 120s linear infinite;
}

.content {
  position: relative;
  z-index: 1;
}

.clouds--front {
  z-index: 2;
  opacity: 0.12; /* 低透明度以保证内容可读性 */
  transform: scale(0.8);
  animation: drift 50s linear infinite reverse;

  /* 可选:为内容周围区域清除遮罩 */
  mask-image: linear-gradient(
    to bottom,
    black 0%,
    transparent 30%,
    transparent 70%,
    black 100%
  );
}

Key Principles

核心原则

  1. Split clouds into 2-3 layers (back, mid, front)
  2. Front clouds use LOW opacity (10-15%) so content remains visible
  3. Always use
    pointer-events: none
    on cloud layers
  4. Use masks to clear space around important content
  5. Vary animation speeds for parallax depth (back = slow, front = fast)
  1. 将云朵分为2-3层(背景、中层、前景)
  2. 前景云朵使用低透明度(10-15%)以保证内容可见
  3. 务必为云朵图层添加
    pointer-events: none
  4. 使用遮罩为重要内容周围留出空间
  5. 差异化动画速度以实现视差深度(背景=慢速,前景=快速)

Blend Modes for Natural Integration

自然融合的混合模式

css
.clouds--front {
  mix-blend-mode: soft-light; /* Blends naturally with content */
  opacity: 0.25;
}

/* Or for white clouds on dark backgrounds */
.clouds--front {
  mix-blend-mode: screen;
  opacity: 0.15;
}
css
.clouds--front {
  mix-blend-mode: soft-light; /* 与内容自然融合 */
  opacity: 0.25;
}

/* 深色背景下的白色云朵 */
.clouds--front {
  mix-blend-mode: screen;
  opacity: 0.15;
}

Content Readability

内容可读性优化

css
/* Add subtle backdrop to cards so text is always readable */
.card {
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(4px); /* Blurs back clouds for extra depth */
}
See
references/layering-strategies.md
for complete patterns including parallax, content-aware masking, and React components.

css
/* 为卡片添加细微背景以保证文本可读性 */
.card {
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: blur(4px); /* 模糊背景云朵以增强深度 */
}
查看
references/layering-strategies.md
获取完整模式,包括视差、内容感知遮罩和React组件。

Core Technique: SVG Filter Chain

核心技术:SVG滤镜链

All atmospheric effects build on this filter architecture:
svg
<svg width="0" height="0">
  <defs>
    <filter id="atmosphere" x="-50%" y="-50%" width="200%" height="200%">
      <!-- 1. Generate noise texture -->
      <feTurbulence
        type="fractalNoise"      <!-- or "turbulence" for water -->
        baseFrequency="0.01"     <!-- Lower = larger shapes -->
        numOctaves="4"           <!-- 3-5 for good detail -->
        seed="1"                 <!-- Change for variation -->
        result="noise"
      />

      <!-- 2. Distort the source -->
      <feDisplacementMap
        in="SourceGraphic"
        in2="noise"
        scale="30"               <!-- Distortion intensity -->
        xChannelSelector="R"
        yChannelSelector="G"
        result="displaced"
      />

      <!-- 3. Soften edges -->
      <feGaussianBlur
        in="displaced"
        stdDeviation="2"
        result="blurred"
      />

      <!-- 4. Add lighting (optional) -->
      <feDiffuseLighting
        in="noise"
        lighting-color="white"
        surfaceScale="2"
        result="lit"
      >
        <feDistantLight azimuth="45" elevation="60" />
      </feDiffuseLighting>

      <!-- 5. Composite layers -->
      <feComposite in="blurred" in2="lit" operator="multiply" />
    </filter>
  </defs>
</svg>
所有大气特效均基于此滤镜架构构建:
svg
<svg width="0" height="0">
  <defs>
    <filter id="atmosphere" x="-50%" y="-50%" width="200%" height="200%">
      <!-- 1. 生成噪声纹理 -->
      <feTurbulence
        type="fractalNoise"      <!-- 或"turbulence"用于水效 -->
        baseFrequency="0.01"     <!-- 值越小,形状越大 -->
        numOctaves="4"           <!-- 3-5为最佳细节 -->
        seed="1"                 <!-- 修改值以生成变体 -->
        result="noise"
      />

      <!-- 2. 扭曲源图形 -->
      <feDisplacementMap
        in="SourceGraphic"
        in2="noise"
        scale="30"               <!-- 扭曲强度 -->
        xChannelSelector="R"
        yChannelSelector="G"
        result="displaced"
      />

      <!-- 3. 柔化边缘 -->
      <feGaussianBlur
        in="displaced"
        stdDeviation="2"
        result="blurred"
      />

      <!-- 4. 添加光照(可选) -->
      <feDiffuseLighting
        in="noise"
        lighting-color="white"
        surfaceScale="2"
        result="lit"
      >
        <feDistantLight azimuth="45" elevation="60" />
      </feDiffuseLighting>

      <!-- 5. 合成图层 -->
      <feComposite in="blurred" in2="lit" operator="multiply" />
    </filter>
  </defs>
</svg>

Key Parameter Reference

关键参数参考

ParameterEffectRangeNotes
type="fractalNoise"
Soft, cloudy-Clouds, smoke, fog
type="turbulence"
Wavy, liquid-Water, waves, ripples
baseFrequency
Shape size0.001-0.1Lower = larger shapes
numOctaves
Detail level1-83-5 optimal, >5 diminishing returns
scale
(displacement)
Distortion0-100Start at 20-30
stdDeviation
(blur)
Softness0-202-5 for clouds, 0-2 for water

参数效果范围说明
type="fractalNoise"
柔和云雾感-云朵、烟雾、雾霭
type="turbulence"
波浪液态感-水流、波浪、涟漪
baseFrequency
形状大小0.001-0.1值越小,形状越大
numOctaves
细节层级1-83-5为最优,超过5收益递减
scale
(位移)
扭曲强度0-100初始值建议20-30
stdDeviation
(模糊)
柔化程度0-20云朵建议2-5,水效建议0-2

SECTION A: CLOUD EFFECTS

A部分:云朵特效

Cloud Type Recipes

云朵类型配置方案

Cloud TypebaseFrequencynumOctavesBlurCharacter
Cumulus (fluffy)0.00843-5Puffy, cotton-like
Cirrus (wispy)0.00351-2Thin, streaky
Stratus (flat)0.01525-8Low, uniform
Storm (dramatic)0.00652-3Dense, textured
Cartoon0.0228-12Soft, simple
云朵类型baseFrequencynumOctaves模糊值特征
积云(蓬松)0.00843-5蓬松如棉
卷云(纤细)0.00351-2纤细条纹状
层云(扁平)0.01525-8低空均匀分布
风暴云(戏剧性)0.00652-3浓密有纹理
卡通云0.0228-12柔和简洁

Multi-Layer Cloud System

多层云朵系统

css
.cloud-layer {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse 200% 100% at 50% 100%,
    rgba(255, 255, 255, 0.9) 0%,
    transparent 70%
  );
  filter: url(#cloud-filter);
}

/* Layer hierarchy: back → front */
.cloud-back {
  opacity: 0.3;
  transform: scale(1.5);
  animation: drift 120s linear infinite;
}

.cloud-mid {
  opacity: 0.5;
  transform: scale(1.2);
  animation: drift 80s linear infinite;
}

.cloud-front {
  opacity: 0.7;
  transform: scale(1);
  animation: drift 50s linear infinite;
}

@keyframes drift {
  from { transform: translateX(-10%); }
  to { transform: translateX(10%); }
}
css
.cloud-layer {
  position: absolute;
  inset: 0;
  background: radial-gradient(
    ellipse 200% 100% at 50% 100%,
    rgba(255, 255, 255, 0.9) 0%,
    transparent 70%
  );
  filter: url(#cloud-filter);
}

/* 图层层级:背景 → 前景 */
.cloud-back {
  opacity: 0.3;
  transform: scale(1.5);
  animation: drift 120s linear infinite;
}

.cloud-mid {
  opacity: 0.5;
  transform: scale(1.2);
  animation: drift 80s linear infinite;
}

.cloud-front {
  opacity: 0.7;
  transform: scale(1);
  animation: drift 50s linear infinite;
}

@keyframes drift {
  from { transform: translateX(-10%); }
  to { transform: translateX(10%); }
}

Cloud Color Palettes

云朵配色方案

css
:root {
  /* Daylight clouds */
  --cloud-white: rgba(255, 255, 255, 0.9);
  --cloud-highlight: rgba(255, 250, 240, 1);
  --cloud-shadow: rgba(180, 190, 210, 0.6);

  /* Sunset clouds */
  --cloud-gold: rgba(255, 200, 100, 0.8);
  --cloud-pink: rgba(255, 150, 180, 0.7);
  --cloud-purple: rgba(180, 100, 200, 0.5);

  /* Storm clouds */
  --storm-dark: rgba(60, 70, 90, 0.9);
  --storm-purple: rgba(80, 60, 100, 0.7);
  --storm-highlight: rgba(200, 210, 230, 0.4);
}

css
:root {
  /* 日间云朵 */
  --cloud-white: rgba(255, 255, 255, 0.9);
  --cloud-highlight: rgba(255, 250, 240, 1);
  --cloud-shadow: rgba(180, 190, 210, 0.6);

  /* 日落云朵 */
  --cloud-gold: rgba(255, 200, 100, 0.8);
  --cloud-pink: rgba(255, 150, 180, 0.7);
  --cloud-purple: rgba(180, 100, 200, 0.5);

  /* 风暴云朵 */
  --storm-dark: rgba(60, 70, 90, 0.9);
  --storm-purple: rgba(80, 60, 100, 0.7);
  --storm-highlight: rgba(200, 210, 230, 0.4);
}

SECTION B: WAVE & WATER EFFECTS

B部分:波浪与水效

Critical Difference: Waves Use
turbulence

关键差异:波浪使用
turbulence

svg
<!-- WATER uses type="turbulence" NOT fractalNoise -->
<feTurbulence
  type="turbulence"
  baseFrequency="0.01 0.03"  <!-- X << Y for horizontal waves -->
  numOctaves="3"
  result="waves"
/>
svg
<!-- 水效使用type="turbulence"而非fractalNoise -->
<feTurbulence
  type="turbulence"
  baseFrequency="0.01 0.03"  <!-- X远小于Y以实现横向波浪 -->
  numOctaves="3"
  result="waves"
/>

Wave Type Recipes

波浪类型配置方案

Wave TypebaseFrequencynumOctavesScaleCharacter
Ocean swell0.005 0.015340Broad, rolling
Lake ripples0.02 0.04215Small, regular
Beach shore0.008 0.02430Approaching, foam
Pool reflection0.03 0.03210Subtle, uniform
波浪类型baseFrequencynumOctaves缩放值特征
海洋巨浪0.005 0.015340宽阔起伏
湖面涟漪0.02 0.04215细小规律
海岸波浪0.008 0.02430渐进带泡沫
泳池倒影0.03 0.03210细微均匀

Animated Wave SVG

动画波浪SVG

svg
<svg viewBox="0 0 1440 320" preserveAspectRatio="none">
  <defs>
    <filter id="wave-distort">
      <feTurbulence
        type="turbulence"
        baseFrequency="0.01 0.02"
        numOctaves="3"
        result="turbulence"
      >
        <animate
          attributeName="baseFrequency"
          dur="20s"
          values="0.01 0.02; 0.015 0.025; 0.01 0.02"
          repeatCount="indefinite"
        />
      </feTurbulence>
      <feDisplacementMap
        in="SourceGraphic"
        in2="turbulence"
        scale="20"
        xChannelSelector="R"
        yChannelSelector="G"
      />
    </filter>
  </defs>

  <path
    fill="var(--ocean-color)"
    filter="url(#wave-distort)"
    d="M0,160 C360,220 720,100 1080,180 C1260,220 1380,140 1440,160 L1440,320 L0,320 Z"
  >
    <animate
      attributeName="d"
      dur="10s"
      repeatCount="indefinite"
      values="
        M0,160 C360,220 720,100 1080,180 C1260,220 1380,140 1440,160 L1440,320 L0,320 Z;
        M0,180 C360,120 720,200 1080,140 C1260,100 1380,180 1440,140 L1440,320 L0,320 Z;
        M0,160 C360,220 720,100 1080,180 C1260,220 1380,140 1440,160 L1440,320 L0,320 Z
      "
    />
  </path>
</svg>
svg
<svg viewBox="0 0 1440 320" preserveAspectRatio="none">
  <defs>
    <filter id="wave-distort">
      <feTurbulence
        type="turbulence"
        baseFrequency="0.01 0.02"
        numOctaves="3"
        result="turbulence"
      >
        <animate
          attributeName="baseFrequency"
          dur="20s"
          values="0.01 0.02; 0.015 0.025; 0.01 0.02"
          repeatCount="indefinite"
        />
      </feTurbulence>
      <feDisplacementMap
        in="SourceGraphic"
        in2="turbulence"
        scale="20"
        xChannelSelector="R"
        yChannelSelector="G"
      />
    </filter>
  </defs>

  <path
    fill="var(--ocean-color)"
    filter="url(#wave-distort)"
    d="M0,160 C360,220 720,100 1080,180 C1260,220 1380,140 1440,160 L1440,320 L0,320 Z"
  >
    <animate
      attributeName="d"
      dur="10s"
      repeatCount="indefinite"
      values="
        M0,160 C360,220 720,100 1080,180 C1260,220 1380,140 1440,160 L1440,320 L0,320 Z;
        M0,180 C360,120 720,200 1080,140 C1260,100 1380,180 1440,140 L1440,320 L0,320 Z;
        M0,160 C360,220 720,100 1080,180 C1260,220 1380,140 1440,160 L1440,320 L0,320 Z
      "
    />
  </path>
</svg>

Ocean Color Palettes

海洋配色方案

css
:root {
  /* Deep ocean */
  --ocean-deep: #0c4a6e;
  --ocean-mid: #0369a1;
  --ocean-surface: #38bdf8;
  --ocean-foam: rgba(255, 255, 255, 0.8);

  /* Tropical */
  --tropical-deep: #047857;
  --tropical-mid: #10b981;
  --tropical-surface: #6ee7b7;

  /* Stormy */
  --stormy-deep: #1e3a5f;
  --stormy-mid: #334155;
  --stormy-surface: #64748b;

  /* Sunset reflection */
  --sunset-water: linear-gradient(
    180deg,
    rgba(251, 146, 60, 0.4) 0%,
    rgba(14, 165, 233, 0.6) 50%,
    #0c4a6e 100%
  );
}

css
:root {
  /* 深海 */
  --ocean-deep: #0c4a6e;
  --ocean-mid: #0369a1;
  --ocean-surface: #38bdf8;
  --ocean-foam: rgba(255, 255, 255, 0.8);

  /* 热带海洋 */
  --tropical-deep: #047857;
  --tropical-mid: #10b981;
  --tropical-surface: #6ee7b7;

  /* 风暴海洋 */
  --stormy-deep: #1e3a5f;
  --stormy-mid: #334155;
  --stormy-surface: #64748b;

  /* 日落倒影 */
  --sunset-water: linear-gradient(
    180deg,
    rgba(251, 146, 60, 0.4) 0%,
    rgba(14, 165, 233, 0.6) 50%,
    #0c4a6e 100%
  );
}

SECTION C: LIGHTNING EFFECTS

C部分:闪电特效

SVG Stroke-Dashoffset Lightning

SVG描边偏移闪电

The most effective technique for lightning uses animated stroke-dashoffset on SVG paths:
svg
<svg viewBox="0 0 100 200" class="lightning">
  <defs>
    <filter id="lightning-glow" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur stdDeviation="3" result="blur" />
      <feMerge>
        <feMergeNode in="blur" />
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
  </defs>

  <path
    class="bolt"
    d="M50,0 L45,40 L55,45 L40,90 L60,95 L35,150 L70,100 L50,95 L65,50 L45,45 L60,10 Z"
    fill="none"
    stroke="white"
    stroke-width="2"
    filter="url(#lightning-glow)"
  />
</svg>
css
.lightning {
  position: absolute;
  pointer-events: none;
  opacity: 0;
}

.bolt {
  stroke-dasharray: 500;
  stroke-dashoffset: 500;
}

.lightning.flash {
  animation: lightning-flash 0.5s ease-out forwards;
}

.lightning.flash .bolt {
  animation: bolt-draw 0.15s ease-out forwards;
}

@keyframes lightning-flash {
  0% { opacity: 0; }
  10% { opacity: 1; }
  20% { opacity: 0.5; }
  30% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes bolt-draw {
  to { stroke-dashoffset: 0; }
}
最有效的闪电特效技术是使用SVG路径的描边偏移动画:
svg
<svg viewBox="0 0 100 200" class="lightning">
  <defs>
    <filter id="lightning-glow" x="-50%" y="-50%" width="200%" height="200%">
      <feGaussianBlur stdDeviation="3" result="blur" />
      <feMerge>
        <feMergeNode in="blur" />
        <feMergeNode in="SourceGraphic" />
      </feMerge>
    </filter>
  </defs>

  <path
    class="bolt"
    d="M50,0 L45,40 L55,45 L40,90 L60,95 L35,150 L70,100 L50,95 L65,50 L45,45 L60,10 Z"
    fill="none"
    stroke="white"
    stroke-width="2"
    filter="url(#lightning-glow)"
  />
</svg>
css
.lightning {
  position: absolute;
  pointer-events: none;
  opacity: 0;
}

.bolt {
  stroke-dasharray: 500;
  stroke-dashoffset: 500;
}

.lightning.flash {
  animation: lightning-flash 0.5s ease-out forwards;
}

.lightning.flash .bolt {
  animation: bolt-draw 0.15s ease-out forwards;
}

@keyframes lightning-flash {
  0% { opacity: 0; }
  10% { opacity: 1; }
  20% { opacity: 0.5; }
  30% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes bolt-draw {
  to { stroke-dashoffset: 0; }
}

Lightning Flash Overlay

闪电闪光覆盖层

css
.lightning-flash-overlay {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, 0);
  pointer-events: none;
  z-index: 1000;
}

.lightning-flash-overlay.active {
  animation: screen-flash 0.3s ease-out;
}

@keyframes screen-flash {
  0% { background: rgba(255, 255, 255, 0); }
  10% { background: rgba(200, 220, 255, 0.4); }
  20% { background: rgba(255, 255, 255, 0); }
  30% { background: rgba(200, 220, 255, 0.2); }
  100% { background: rgba(255, 255, 255, 0); }
}
css
.lightning-flash-overlay {
  position: fixed;
  inset: 0;
  background: rgba(255, 255, 255, 0);
  pointer-events: none;
  z-index: 1000;
}

.lightning-flash-overlay.active {
  animation: screen-flash 0.3s ease-out;
}

@keyframes screen-flash {
  0% { background: rgba(255, 255, 255, 0); }
  10% { background: rgba(200, 220, 255, 0.4); }
  20% { background: rgba(255, 255, 255, 0); }
  30% { background: rgba(200, 220, 255, 0.2); }
  100% { background: rgba(255, 255, 255, 0); }
}

Branching Lightning Pattern

分支闪电图案生成

javascript
function generateLightningPath(startX, startY, endY, segments = 8) {
  let path = `M${startX},${startY}`;
  let x = startX;
  let y = startY;
  const segmentHeight = (endY - startY) / segments;

  for (let i = 0; i < segments; i++) {
    const jitter = (Math.random() - 0.5) * 30;
    x += jitter;
    y += segmentHeight;
    path += ` L${x},${y}`;

    // Random branch (20% chance)
    if (Math.random() < 0.2) {
      const branchX = x + (Math.random() - 0.5) * 40;
      const branchY = y + segmentHeight * 0.5;
      path += ` M${x},${y} L${branchX},${branchY} M${x},${y}`;
    }
  }

  return path;
}

javascript
function generateLightningPath(startX, startY, endY, segments = 8) {
  let path = `M${startX},${startY}`;
  let x = startX;
  let y = startY;
  const segmentHeight = (endY - startY) / segments;

  for (let i = 0; i < segments; i++) {
    const jitter = (Math.random() - 0.5) * 30;
    x += jitter;
    y += segmentHeight;
    path += ` L${x},${y}`;

    // 随机生成分支(20%概率)
    if (Math.random() < 0.2) {
      const branchX = x + (Math.random() - 0.5) * 40;
      const branchY = y + segmentHeight * 0.5;
      path += ` M${x},${y} L${branchX},${branchY} M${x},${y}`;
    }
  }

  return path;
}

SECTION D: RAIN EFFECTS

D部分:降雨特效

CSS-Only Rain with Custom Properties

纯CSS降雨(自定义属性)

css
.rain-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.raindrop {
  position: absolute;
  width: 2px;
  background: linear-gradient(
    180deg,
    transparent 0%,
    rgba(174, 194, 224, 0.5) 50%,
    rgba(174, 194, 224, 0.8) 100%
  );
  border-radius: 0 0 2px 2px;
  animation: rain-fall var(--fall-duration) linear infinite;
  animation-delay: var(--delay);
  left: var(--x);
  height: var(--length);
  opacity: var(--opacity);
}

@keyframes rain-fall {
  0% {
    transform: translateY(-100vh);
  }
  100% {
    transform: translateY(100vh);
  }
}
css
.rain-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.raindrop {
  position: absolute;
  width: 2px;
  background: linear-gradient(
    180deg,
    transparent 0%,
    rgba(174, 194, 224, 0.5) 50%,
    rgba(174, 194, 224, 0.8) 100%
  );
  border-radius: 0 0 2px 2px;
  animation: rain-fall var(--fall-duration) linear infinite;
  animation-delay: var(--delay);
  left: var(--x);
  height: var(--length);
  opacity: var(--opacity);
}

@keyframes rain-fall {
  0% {
    transform: translateY(-100vh);
  }
  100% {
    transform: translateY(100vh);
  }
}

Rain Generator (JavaScript)

降雨生成器(JavaScript)

javascript
function createRain(container, dropCount = 100) {
  for (let i = 0; i < dropCount; i++) {
    const drop = document.createElement('div');
    drop.className = 'raindrop';
    drop.style.setProperty('--x', `${Math.random() * 100}%`);
    drop.style.setProperty('--delay', `${Math.random() * 2}s`);
    drop.style.setProperty('--fall-duration', `${0.5 + Math.random() * 0.5}s`);
    drop.style.setProperty('--length', `${15 + Math.random() * 20}px`);
    drop.style.setProperty('--opacity', `${0.3 + Math.random() * 0.5}`);
    container.appendChild(drop);
  }
}
javascript
function createRain(container, dropCount = 100) {
  for (let i = 0; i < dropCount; i++) {
    const drop = document.createElement('div');
    drop.className = 'raindrop';
    drop.style.setProperty('--x', `${Math.random() * 100}%`);
    drop.style.setProperty('--delay', `${Math.random() * 2}s`);
    drop.style.setProperty('--fall-duration', `${0.5 + Math.random() * 0.5}s`);
    drop.style.setProperty('--length', `${15 + Math.random() * 20}px`);
    drop.style.setProperty('--opacity', `${0.3 + Math.random() * 0.5}`);
    container.appendChild(drop);
  }
}

Rain Intensity Presets

降雨强度预设

css
/* Light drizzle */
.rain-light {
  --drop-count: 50;
  --fall-duration-base: 1.2s;
  --drop-opacity: 0.3;
}

/* Moderate rain */
.rain-moderate {
  --drop-count: 150;
  --fall-duration-base: 0.8s;
  --drop-opacity: 0.5;
}

/* Heavy downpour */
.rain-heavy {
  --drop-count: 300;
  --fall-duration-base: 0.5s;
  --drop-opacity: 0.7;
}
css
/* 小雨 */
.rain-light {
  --drop-count: 50;
  --fall-duration-base: 1.2s;
  --drop-opacity: 0.3;
}

/* 中雨 */
.rain-moderate {
  --drop-count: 150;
  --fall-duration-base: 0.8s;
  --drop-opacity: 0.5;
}

/* 大雨 */
.rain-heavy {
  --drop-count: 300;
  --fall-duration-base: 0.5s;
  --drop-opacity: 0.7;
}

Rain + Wind Angle

降雨+风向角度

css
.raindrop.windy {
  animation: rain-fall-diagonal var(--fall-duration) linear infinite;
}

@keyframes rain-fall-diagonal {
  0% {
    transform: translate(-50vw, -100vh) rotate(15deg);
  }
  100% {
    transform: translate(50vw, 100vh) rotate(15deg);
  }
}

css
.raindrop.windy {
  animation: rain-fall-diagonal var(--fall-duration) linear infinite;
}

@keyframes rain-fall-diagonal {
  0% {
    transform: translate(-50vw, -100vh) rotate(15deg);
  }
  100% {
    transform: translate(50vw, 100vh) rotate(15deg);
  }
}

SECTION E: FOG & MIST EFFECTS

E部分:雾霭特效

Multi-Layer Fog System

多层雾霭系统

css
.fog-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.fog-layer {
  position: absolute;
  width: 200%;
  height: 100%;
  background: url("data:image/svg+xml,...") repeat-x;
  opacity: 0.3;
  filter: url(#fog-filter);
}

.fog-back {
  animation: fog-drift 60s linear infinite;
  opacity: 0.2;
  transform: scale(1.5);
}

.fog-mid {
  animation: fog-drift 40s linear infinite reverse;
  opacity: 0.3;
  transform: scale(1.2);
}

.fog-front {
  animation: fog-drift 25s linear infinite;
  opacity: 0.4;
}

@keyframes fog-drift {
  from { transform: translateX(-50%); }
  to { transform: translateX(0%); }
}
css
.fog-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.fog-layer {
  position: absolute;
  width: 200%;
  height: 100%;
  background: url("data:image/svg+xml,...") repeat-x;
  opacity: 0.3;
  filter: url(#fog-filter);
}

.fog-back {
  animation: fog-drift 60s linear infinite;
  opacity: 0.2;
  transform: scale(1.5);
}

.fog-mid {
  animation: fog-drift 40s linear infinite reverse;
  opacity: 0.3;
  transform: scale(1.2);
}

.fog-front {
  animation: fog-drift 25s linear infinite;
  opacity: 0.4;
}

@keyframes fog-drift {
  from { transform: translateX(-50%); }
  to { transform: translateX(0%); }
}

SVG Fog Filter

SVG雾霭滤镜

svg
<filter id="fog-filter" x="-50%" y="-50%" width="200%" height="200%">
  <feTurbulence
    type="fractalNoise"
    baseFrequency="0.003"
    numOctaves="4"
    seed="5"
    result="noise"
  />
  <feGaussianBlur in="noise" stdDeviation="20" result="blur" />
  <feColorMatrix
    type="matrix"
    values="1 0 0 0 0
            0 1 0 0 0
            0 0 1 0 0
            0 0 0 0.5 0"
    result="faded"
  />
</filter>
svg
<filter id="fog-filter" x="-50%" y="-50%" width="200%" height="200%">
  <feTurbulence
    type="fractalNoise"
    baseFrequency="0.003"
    numOctaves="4"
    seed="5"
    result="noise"
  />
  <feGaussianBlur in="noise" stdDeviation="20" result="blur" />
  <feColorMatrix
    type="matrix"
    values="1 0 0 0 0
            0 1 0 0 0
            0 0 1 0 0
            0 0 0 0.5 0"
    result="faded"
  />
</filter>

Fog Density Variations

雾霭密度变体

css
:root {
  /* Light haze */
  --fog-light: rgba(255, 255, 255, 0.2);
  --fog-blur-light: 10px;

  /* Morning mist */
  --fog-mist: rgba(200, 210, 230, 0.4);
  --fog-blur-mist: 20px;

  /* Dense fog */
  --fog-dense: rgba(180, 190, 210, 0.6);
  --fog-blur-dense: 40px;

  /* Eerie fog (horror) */
  --fog-eerie: rgba(100, 120, 140, 0.5);
  --fog-blur-eerie: 30px;
}
css
:root {
  /* 轻度薄雾 */
  --fog-light: rgba(255, 255, 255, 0.2);
  --fog-blur-light: 10px;

  /* 晨雾 */
  --fog-mist: rgba(200, 210, 230, 0.4);
  --fog-blur-mist: 20px;

  /* 浓雾 */
  --fog-dense: rgba(180, 190, 210, 0.6);
  --fog-blur-dense: 40px;

  /* 诡异雾霭(恐怖风格) */
  --fog-eerie: rgba(100, 120, 140, 0.5);
  --fog-blur-eerie: 30px;
}

Ground-Hugging Mist

贴地薄雾

css
.ground-mist {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 30%;
  background: linear-gradient(
    to top,
    rgba(255, 255, 255, 0.6) 0%,
    rgba(255, 255, 255, 0.3) 40%,
    transparent 100%
  );
  filter: url(#fog-filter);
  animation: mist-breathe 8s ease-in-out infinite;
}

@keyframes mist-breathe {
  0%, 100% {
    opacity: 0.5;
    transform: scaleY(1);
  }
  50% {
    opacity: 0.7;
    transform: scaleY(1.1);
  }
}

css
.ground-mist {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 30%;
  background: linear-gradient(
    to top,
    rgba(255, 255, 255, 0.6) 0%,
    rgba(255, 255, 255, 0.3) 40%,
    transparent 100%
  );
  filter: url(#fog-filter);
  animation: mist-breathe 8s ease-in-out infinite;
}

@keyframes mist-breathe {
  0%, 100% {
    opacity: 0.5;
    transform: scaleY(1);
  }
  50% {
    opacity: 0.7;
    transform: scaleY(1.1);
  }
}

SECTION F: TWILIGHT & SKY GRADIENTS

F部分:黄昏与天空渐变

Sky Time Progression

天空时段渐变

css
:root {
  /* Pre-dawn (5:00-5:30) */
  --sky-predawn: linear-gradient(
    to top,
    #1a1a2e 0%,
    #16213e 30%,
    #0f3460 60%,
    #1a1a2e 100%
  );

  /* Dawn (5:30-6:30) */
  --sky-dawn: linear-gradient(
    to top,
    #ff6b6b 0%,
    #feca57 20%,
    #ff9ff3 40%,
    #54a0ff 70%,
    #1a1a2e 100%
  );

  /* Golden hour (6:30-7:30) */
  --sky-golden: linear-gradient(
    to top,
    #ff9a56 0%,
    #ffbe76 30%,
    #ffeaa7 50%,
    #74b9ff 80%,
    #0984e3 100%
  );

  /* Midday (10:00-14:00) */
  --sky-midday: linear-gradient(
    to top,
    #74b9ff 0%,
    #0984e3 50%,
    #0652dd 100%
  );

  /* Sunset (17:30-18:30) */
  --sky-sunset: linear-gradient(
    to top,
    #e17055 0%,
    #fdcb6e 20%,
    #f8a5c2 40%,
    #686de0 70%,
    #30336b 100%
  );

  /* Dusk (18:30-19:30) */
  --sky-dusk: linear-gradient(
    to top,
    #4a69bd 0%,
    #6a89cc 30%,
    #b8e994 10%,
    #e55039 5%,
    #1e3799 60%,
    #0c2461 100%
  );

  /* Night (20:00+) */
  --sky-night: linear-gradient(
    to top,
    #0c2461 0%,
    #1e3799 40%,
    #0a1931 100%
  );
}
css
:root {
  /* 黎明前(5:00-5:30) */
  --sky-predawn: linear-gradient(
    to top,
    #1a1a2e 0%,
    #16213e 30%,
    #0f3460 60%,
    #1a1a2e 100%
  );

  /* 黎明(5:30-6:30) */
  --sky-dawn: linear-gradient(
    to top,
    #ff6b6b 0%,
    #feca57 20%,
    #ff9ff3 40%,
    #54a0ff 70%,
    #1a1a2e 100%
  );

  /* 黄金时刻(6:30-7:30) */
  --sky-golden: linear-gradient(
    to top,
    #ff9a56 0%,
    #ffbe76 30%,
    #ffeaa7 50%,
    #74b9ff 80%,
    #0984e3 100%
  );

  /* 正午(10:00-14:00) */
  --sky-midday: linear-gradient(
    to top,
    #74b9ff 0%,
    #0984e3 50%,
    #0652dd 100%
  );

  /* 日落(17:30-18:30) */
  --sky-sunset: linear-gradient(
    to top,
    #e17055 0%,
    #fdcb6e 20%,
    #f8a5c2 40%,
    #686de0 70%,
    #30336b 100%
  );

  /* 黄昏(18:30-19:30) */
  --sky-dusk: linear-gradient(
    to top,
    #4a69bd 0%,
    #6a89cc 30%,
    #b8e994 10%,
    #e55039 5%,
    #1e3799 60%,
    #0c2461 100%
  );

  /* 夜晚(20:00+) */
  --sky-night: linear-gradient(
    to top,
    #0c2461 0%,
    #1e3799 40%,
    #0a1931 100%
  );
}

Animated Sky Transition

动画天空过渡

css
.sky-canvas {
  background: var(--sky-midday);
  transition: background 3s ease-in-out;
}

.sky-canvas[data-time="dawn"] { background: var(--sky-dawn); }
.sky-canvas[data-time="golden"] { background: var(--sky-golden); }
.sky-canvas[data-time="midday"] { background: var(--sky-midday); }
.sky-canvas[data-time="sunset"] { background: var(--sky-sunset); }
.sky-canvas[data-time="dusk"] { background: var(--sky-dusk); }
.sky-canvas[data-time="night"] { background: var(--sky-night); }
css
.sky-canvas {
  background: var(--sky-midday);
  transition: background 3s ease-in-out;
}

.sky-canvas[data-time="dawn"] { background: var(--sky-dawn); }
.sky-canvas[data-time="golden"] { background: var(--sky-golden); }
.sky-canvas[data-time="midday"] { background: var(--sky-midday); }
.sky-canvas[data-time="sunset"] { background: var(--sky-sunset); }
.sky-canvas[data-time="dusk"] { background: var(--sky-dusk); }
.sky-canvas[data-time="night"] { background: var(--sky-night); }

Sun/Moon Position System

日月定位系统

css
.celestial-body {
  position: absolute;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  transition: all 2s cubic-bezier(0.4, 0, 0.2, 1);
}

.sun {
  background: radial-gradient(
    circle,
    #fff7e6 0%,
    #ffd93d 40%,
    #ff8c00 100%
  );
  box-shadow:
    0 0 40px 10px rgba(255, 200, 50, 0.6),
    0 0 80px 30px rgba(255, 150, 0, 0.3);
}

.moon {
  background: radial-gradient(
    circle at 30% 30%,
    #f5f5f5 0%,
    #e0e0e0 50%,
    #bdbdbd 100%
  );
  box-shadow:
    0 0 20px 5px rgba(255, 255, 255, 0.3),
    inset -10px -10px 20px rgba(0, 0, 0, 0.1);
}

css
.celestial-body {
  position: absolute;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  transition: all 2s cubic-bezier(0.4, 0, 0.2, 1);
}

.sun {
  background: radial-gradient(
    circle,
    #fff7e6 0%,
    #ffd93d 40%,
    #ff8c00 100%
  );
  box-shadow:
    0 0 40px 10px rgba(255, 200, 50, 0.6),
    0 0 80px 30px rgba(255, 150, 0, 0.3);
}

.moon {
  background: radial-gradient(
    circle at 30% 30%,
    #f5f5f5 0%,
    #e0e0e0 50%,
    #bdbdbd 100%
  );
  box-shadow:
    0 0 20px 5px rgba(255, 255, 255, 0.3),
    inset -10px -10px 20px rgba(0, 0, 0, 0.1);
}

SECTION G: AURORA BOREALIS

G部分:极光特效

Stacked Gradient Aurora

堆叠渐变极光

css
.aurora-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: linear-gradient(to top, #0a0a1a 0%, #1a1a3a 100%);
}

.aurora-band {
  position: absolute;
  top: 10%;
  left: -50%;
  width: 200%;
  height: 40%;
  opacity: 0.6;
  mix-blend-mode: screen;
  filter: blur(30px);
}

.aurora-green {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(0, 255, 128, 0.4) 20%,
    rgba(0, 255, 200, 0.6) 50%,
    rgba(0, 255, 128, 0.4) 80%,
    transparent 100%
  );
  animation: aurora-wave 15s ease-in-out infinite;
}

.aurora-purple {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(138, 43, 226, 0.3) 25%,
    rgba(75, 0, 130, 0.5) 50%,
    rgba(138, 43, 226, 0.3) 75%,
    transparent 100%
  );
  animation: aurora-wave 20s ease-in-out infinite reverse;
  animation-delay: -5s;
}

.aurora-blue {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(0, 150, 255, 0.3) 30%,
    rgba(0, 200, 255, 0.4) 50%,
    rgba(0, 150, 255, 0.3) 70%,
    transparent 100%
  );
  animation: aurora-wave 18s ease-in-out infinite;
  animation-delay: -8s;
}

@keyframes aurora-wave {
  0%, 100% {
    transform: translateX(-20%) scaleY(1) skewX(-5deg);
    opacity: 0.4;
  }
  25% {
    transform: translateX(-10%) scaleY(1.2) skewX(5deg);
    opacity: 0.7;
  }
  50% {
    transform: translateX(0%) scaleY(0.8) skewX(-3deg);
    opacity: 0.5;
  }
  75% {
    transform: translateX(10%) scaleY(1.1) skewX(3deg);
    opacity: 0.6;
  }
}
css
.aurora-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: linear-gradient(to top, #0a0a1a 0%, #1a1a3a 100%);
}

.aurora-band {
  position: absolute;
  top: 10%;
  left: -50%;
  width: 200%;
  height: 40%;
  opacity: 0.6;
  mix-blend-mode: screen;
  filter: blur(30px);
}

.aurora-green {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(0, 255, 128, 0.4) 20%,
    rgba(0, 255, 200, 0.6) 50%,
    rgba(0, 255, 128, 0.4) 80%,
    transparent 100%
  );
  animation: aurora-wave 15s ease-in-out infinite;
}

.aurora-purple {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(138, 43, 226, 0.3) 25%,
    rgba(75, 0, 130, 0.5) 50%,
    rgba(138, 43, 226, 0.3) 75%,
    transparent 100%
  );
  animation: aurora-wave 20s ease-in-out infinite reverse;
  animation-delay: -5s;
}

.aurora-blue {
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(0, 150, 255, 0.3) 30%,
    rgba(0, 200, 255, 0.4) 50%,
    rgba(0, 150, 255, 0.3) 70%,
    transparent 100%
  );
  animation: aurora-wave 18s ease-in-out infinite;
  animation-delay: -8s;
}

@keyframes aurora-wave {
  0%, 100% {
    transform: translateX(-20%) scaleY(1) skewX(-5deg);
    opacity: 0.4;
  }
  25% {
    transform: translateX(-10%) scaleY(1.2) skewX(5deg);
    opacity: 0.7;
  }
  50% {
    transform: translateX(0%) scaleY(0.8) skewX(-3deg);
    opacity: 0.5;
  }
  75% {
    transform: translateX(10%) scaleY(1.1) skewX(3deg);
    opacity: 0.6;
  }
}

Aurora Curtain Effect

极光幕布效果

css
.aurora-curtain {
  position: absolute;
  top: 0;
  width: 100%;
  height: 60%;
  background: repeating-linear-gradient(
    90deg,
    transparent 0px,
    rgba(0, 255, 150, 0.1) 2px,
    transparent 4px
  );
  filter: blur(2px);
  animation: curtain-shimmer 3s ease-in-out infinite;
}

@keyframes curtain-shimmer {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 0.6; }
}
css
.aurora-curtain {
  position: absolute;
  top: 0;
  width: 100%;
  height: 60%;
  background: repeating-linear-gradient(
    90deg,
    transparent 0px,
    rgba(0, 255, 150, 0.1) 2px,
    transparent 4px
  );
  filter: blur(2px);
  animation: curtain-shimmer 3s ease-in-out infinite;
}

@keyframes curtain-shimmer {
  0%, 100% { opacity: 0.3; }
  50% { opacity: 0.6; }
}

Aurora Color Palettes

极光配色方案

css
:root {
  /* Classic green */
  --aurora-green-1: rgba(0, 255, 128, 0.6);
  --aurora-green-2: rgba(50, 255, 180, 0.4);

  /* Purple/violet */
  --aurora-purple-1: rgba(138, 43, 226, 0.5);
  --aurora-purple-2: rgba(186, 85, 211, 0.4);

  /* Blue tones */
  --aurora-blue-1: rgba(0, 191, 255, 0.4);
  --aurora-blue-2: rgba(65, 105, 225, 0.3);

  /* Rare red (high activity) */
  --aurora-red-1: rgba(255, 69, 0, 0.3);
  --aurora-red-2: rgba(255, 99, 71, 0.2);
}

css
:root {
  /* 经典绿色 */
  --aurora-green-1: rgba(0, 255, 128, 0.6);
  --aurora-green-2: rgba(50, 255, 180, 0.4);

  /* 紫色 */
  --aurora-purple-1: rgba(138, 43, 226, 0.5);
  --aurora-purple-2: rgba(186, 85, 211, 0.4);

  /* 蓝色调 */
  --aurora-blue-1: rgba(0, 191, 255, 0.4);
  --aurora-blue-2: rgba(65, 105, 225, 0.3);

  /* 罕见红色(高活动度) */
  --aurora-red-1: rgba(255, 69, 0, 0.3);
  --aurora-red-2: rgba(255, 99, 71, 0.2);
}

SECTION H: GOD RAYS (CREPUSCULAR RAYS)

H部分:耶稣光(曙暮辉)

Conic Gradient God Rays

锥形渐变耶稣光

css
.god-rays-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.god-rays {
  position: absolute;
  top: -50%;
  left: 50%;
  transform: translateX(-50%);
  width: 200%;
  height: 200%;
  background: conic-gradient(
    from 180deg at 50% 0%,
    transparent 0deg,
    rgba(255, 248, 220, 0.2) 5deg,
    transparent 10deg,
    transparent 20deg,
    rgba(255, 248, 220, 0.15) 25deg,
    transparent 30deg,
    transparent 45deg,
    rgba(255, 248, 220, 0.2) 50deg,
    transparent 55deg,
    transparent 70deg,
    rgba(255, 248, 220, 0.1) 75deg,
    transparent 80deg,
    transparent 100deg,
    rgba(255, 248, 220, 0.15) 105deg,
    transparent 110deg,
    transparent 130deg,
    rgba(255, 248, 220, 0.2) 135deg,
    transparent 140deg,
    transparent 160deg,
    rgba(255, 248, 220, 0.1) 165deg,
    transparent 170deg,
    transparent 180deg
  );
  mask-image: radial-gradient(
    ellipse 100% 100% at 50% 0%,
    black 0%,
    transparent 70%
  );
  animation: rays-pulse 8s ease-in-out infinite;
}

@keyframes rays-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 0.9; }
}
css
.god-rays-container {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
}

.god-rays {
  position: absolute;
  top: -50%;
  left: 50%;
  transform: translateX(-50%);
  width: 200%;
  height: 200%;
  background: conic-gradient(
    from 180deg at 50% 0%,
    transparent 0deg,
    rgba(255, 248, 220, 0.2) 5deg,
    transparent 10deg,
    transparent 20deg,
    rgba(255, 248, 220, 0.15) 25deg,
    transparent 30deg,
    transparent 45deg,
    rgba(255, 248, 220, 0.2) 50deg,
    transparent 55deg,
    transparent 70deg,
    rgba(255, 248, 220, 0.1) 75deg,
    transparent 80deg,
    transparent 100deg,
    rgba(255, 248, 220, 0.15) 105deg,
    transparent 110deg,
    transparent 130deg,
    rgba(255, 248, 220, 0.2) 135deg,
    transparent 140deg,
    transparent 160deg,
    rgba(255, 248, 220, 0.1) 165deg,
    transparent 170deg,
    transparent 180deg
  );
  mask-image: radial-gradient(
    ellipse 100% 100% at 50% 0%,
    black 0%,
    transparent 70%
  );
  animation: rays-pulse 8s ease-in-out infinite;
}

@keyframes rays-pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 0.9; }
}

Through-Window God Rays

透过窗户的耶稣光

css
.window-rays {
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    135deg,
    transparent 0%,
    transparent 30%,
    rgba(255, 248, 220, 0.3) 30%,
    rgba(255, 248, 220, 0.1) 35%,
    transparent 35%,
    transparent 45%,
    rgba(255, 248, 220, 0.25) 45%,
    rgba(255, 248, 220, 0.05) 52%,
    transparent 52%,
    transparent 60%,
    rgba(255, 248, 220, 0.2) 60%,
    rgba(255, 248, 220, 0.05) 68%,
    transparent 68%
  );
  filter: blur(20px);
  mix-blend-mode: overlay;
}
css
.window-rays {
  position: absolute;
  width: 100%;
  height: 100%;
  background: linear-gradient(
    135deg,
    transparent 0%,
    transparent 30%,
    rgba(255, 248, 220, 0.3) 30%,
    rgba(255, 248, 220, 0.1) 35%,
    transparent 35%,
    transparent 45%,
    rgba(255, 248, 220, 0.25) 45%,
    rgba(255, 248, 220, 0.05) 52%,
    transparent 52%,
    transparent 60%,
    rgba(255, 248, 220, 0.2) 60%,
    rgba(255, 248, 220, 0.05) 68%,
    transparent 68%
  );
  filter: blur(20px);
  mix-blend-mode: overlay;
}

Animated Ray Rotation

动画光线旋转

css
.rotating-rays {
  animation: rays-rotate 120s linear infinite;
}

@keyframes rays-rotate {
  from { transform: translateX(-50%) rotate(0deg); }
  to { transform: translateX(-50%) rotate(360deg); }
}

css
.rotating-rays {
  animation: rays-rotate 120s linear infinite;
}

@keyframes rays-rotate {
  from { transform: translateX(-50%) rotate(0deg); }
  to { transform: translateX(-50%) rotate(360deg); }
}

SECTION I: LENS FLARE & CAMERA EFFECTS

I部分:镜头光晕与相机特效

Radial Gradient Lens Flare

径向渐变镜头光晕

css
.lens-flare-container {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.flare-source {
  position: absolute;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 1) 0%,
    rgba(255, 240, 200, 0.8) 20%,
    rgba(255, 200, 100, 0.4) 40%,
    transparent 70%
  );
  box-shadow:
    0 0 60px 30px rgba(255, 200, 100, 0.5),
    0 0 120px 60px rgba(255, 150, 50, 0.3);
}

.flare-artifact {
  position: absolute;
  border-radius: 50%;
  opacity: 0.3;
}

.flare-artifact.hexagon {
  width: 40px;
  height: 40px;
  background: radial-gradient(
    circle,
    rgba(100, 200, 255, 0.4) 0%,
    rgba(100, 200, 255, 0.1) 50%,
    transparent 70%
  );
  clip-path: polygon(
    50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%
  );
}

.flare-artifact.streak {
  width: 200px;
  height: 2px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 200, 150, 0.6) 30%,
    rgba(255, 255, 255, 0.8) 50%,
    rgba(255, 200, 150, 0.6) 70%,
    transparent 100%
  );
  transform-origin: center;
}

.flare-artifact.ring {
  width: 100px;
  height: 100px;
  border: 2px solid rgba(255, 200, 150, 0.2);
  background: transparent;
}
css
.lens-flare-container {
  position: absolute;
  inset: 0;
  pointer-events: none;
  overflow: hidden;
}

.flare-source {
  position: absolute;
  width: 80px;
  height: 80px;
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 1) 0%,
    rgba(255, 240, 200, 0.8) 20%,
    rgba(255, 200, 100, 0.4) 40%,
    transparent 70%
  );
  box-shadow:
    0 0 60px 30px rgba(255, 200, 100, 0.5),
    0 0 120px 60px rgba(255, 150, 50, 0.3);
}

.flare-artifact {
  position: absolute;
  border-radius: 50%;
  opacity: 0.3;
}

.flare-artifact.hexagon {
  width: 40px;
  height: 40px;
  background: radial-gradient(
    circle,
    rgba(100, 200, 255, 0.4) 0%,
    rgba(100, 200, 255, 0.1) 50%,
    transparent 70%
  );
  clip-path: polygon(
    50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%
  );
}

.flare-artifact.streak {
  width: 200px;
  height: 2px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 200, 150, 0.6) 30%,
    rgba(255, 255, 255, 0.8) 50%,
    rgba(255, 200, 150, 0.6) 70%,
    transparent 100%
  );
  transform-origin: center;
}

.flare-artifact.ring {
  width: 100px;
  height: 100px;
  border: 2px solid rgba(255, 200, 150, 0.2);
  background: transparent;
}

Anamorphic Flare (Cinematic)

变形宽屏光晕(电影风格)

css
.anamorphic-flare {
  position: absolute;
  width: 100%;
  height: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(100, 180, 255, 0.3) 20%,
    rgba(255, 255, 255, 0.6) 50%,
    rgba(100, 180, 255, 0.3) 80%,
    transparent 100%
  );
  filter: blur(2px);
  animation: anamorphic-pulse 4s ease-in-out infinite;
}

@keyframes anamorphic-pulse {
  0%, 100% {
    opacity: 0.4;
    transform: translateY(-50%) scaleX(0.8);
  }
  50% {
    opacity: 0.7;
    transform: translateY(-50%) scaleX(1.2);
  }
}
css
.anamorphic-flare {
  position: absolute;
  width: 100%;
  height: 4px;
  top: 50%;
  transform: translateY(-50%);
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(100, 180, 255, 0.3) 20%,
    rgba(255, 255, 255, 0.6) 50%,
    rgba(100, 180, 255, 0.3) 80%,
    transparent 100%
  );
  filter: blur(2px);
  animation: anamorphic-pulse 4s ease-in-out infinite;
}

@keyframes anamorphic-pulse {
  0%, 100% {
    opacity: 0.4;
    transform: translateY(-50%) scaleX(0.8);
  }
  50% {
    opacity: 0.7;
    transform: translateY(-50%) scaleX(1.2);
  }
}

Dynamic Flare Following Mouse

跟随鼠标的动态光晕

javascript
function createDynamicFlare(container, sourcePosition) {
  const center = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
  const direction = {
    x: center.x - sourcePosition.x,
    y: center.y - sourcePosition.y
  };

  // Create artifacts along the flare line
  const artifactCount = 5;
  for (let i = 0; i < artifactCount; i++) {
    const t = (i + 1) / (artifactCount + 1);
    const artifact = document.createElement('div');
    artifact.className = 'flare-artifact hexagon';
    artifact.style.left = `${sourcePosition.x + direction.x * t * 1.5}px`;
    artifact.style.top = `${sourcePosition.y + direction.y * t * 1.5}px`;
    artifact.style.opacity = 0.3 - (i * 0.05);
    artifact.style.transform = `scale(${1 - i * 0.15})`;
    container.appendChild(artifact);
  }
}

javascript
function createDynamicFlare(container, sourcePosition) {
  const center = { x: window.innerWidth / 2, y: window.innerHeight / 2 };
  const direction = {
    x: center.x - sourcePosition.x,
    y: center.y - sourcePosition.y
  };

  // 沿光晕路径创建伪影
  const artifactCount = 5;
  for (let i = 0; i < artifactCount; i++) {
    const t = (i + 1) / (artifactCount + 1);
    const artifact = document.createElement('div');
    artifact.className = 'flare-artifact hexagon';
    artifact.style.left = `${sourcePosition.x + direction.x * t * 1.5}px`;
    artifact.style.top = `${sourcePosition.y + direction.y * t * 1.5}px`;
    artifact.style.opacity = 0.3 - (i * 0.05);
    artifact.style.transform = `scale(${1 - i * 0.15})`;
    container.appendChild(artifact);
  }
}

SECTION J: OCEAN SPRAY & SPLASH

J部分:海浪喷雾特效

Particle-Based Spray

粒子喷雾

css
.spray-container {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 40%;
  overflow: hidden;
  pointer-events: none;
}

.spray-particle {
  position: absolute;
  width: var(--size, 4px);
  height: var(--size, 4px);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 0.9) 0%,
    rgba(200, 230, 255, 0.6) 50%,
    transparent 100%
  );
  animation: spray-rise var(--duration, 1s) ease-out forwards;
  animation-delay: var(--delay, 0s);
}

@keyframes spray-rise {
  0% {
    transform: translateY(0) scale(1);
    opacity: 0.8;
  }
  50% {
    opacity: 0.6;
  }
  100% {
    transform: translateY(-100px) translateX(var(--drift, 20px)) scale(0.3);
    opacity: 0;
  }
}
css
.spray-container {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 40%;
  overflow: hidden;
  pointer-events: none;
}

.spray-particle {
  position: absolute;
  width: var(--size, 4px);
  height: var(--size, 4px);
  border-radius: 50%;
  background: radial-gradient(
    circle,
    rgba(255, 255, 255, 0.9) 0%,
    rgba(200, 230, 255, 0.6) 50%,
    transparent 100%
  );
  animation: spray-rise var(--duration, 1s) ease-out forwards;
  animation-delay: var(--delay, 0s);
}

@keyframes spray-rise {
  0% {
    transform: translateY(0) scale(1);
    opacity: 0.8;
  }
  50% {
    opacity: 0.6;
  }
  100% {
    transform: translateY(-100px) translateX(var(--drift, 20px)) scale(0.3);
    opacity: 0;
  }
}

Spray Generator

喷雾生成器

javascript
function createSpray(container, intensity = 'medium') {
  const config = {
    light: { count: 20, maxSize: 6, maxDuration: 1.2 },
    medium: { count: 50, maxSize: 10, maxDuration: 1.5 },
    heavy: { count: 100, maxSize: 15, maxDuration: 2 }
  }[intensity];

  for (let i = 0; i < config.count; i++) {
    const particle = document.createElement('div');
    particle.className = 'spray-particle';
    particle.style.setProperty('--size', `${2 + Math.random() * config.maxSize}px`);
    particle.style.setProperty('--duration', `${0.5 + Math.random() * config.maxDuration}s`);
    particle.style.setProperty('--delay', `${Math.random() * 0.5}s`);
    particle.style.setProperty('--drift', `${(Math.random() - 0.5) * 60}px`);
    particle.style.left = `${Math.random() * 100}%`;
    particle.style.bottom = '0';
    container.appendChild(particle);

    // Remove after animation
    setTimeout(() => particle.remove(), (0.5 + config.maxDuration) * 1000 + 500);
  }
}
javascript
function createSpray(container, intensity = 'medium') {
  const config = {
    light: { count: 20, maxSize: 6, maxDuration: 1.2 },
    medium: { count: 50, maxSize: 10, maxDuration: 1.5 },
    heavy: { count: 100, maxSize: 15, maxDuration: 2 }
  }[intensity];

  for (let i = 0; i < config.count; i++) {
    const particle = document.createElement('div');
    particle.className = 'spray-particle';
    particle.style.setProperty('--size', `${2 + Math.random() * config.maxSize}px`);
    particle.style.setProperty('--duration', `${0.5 + Math.random() * config.maxDuration}s`);
    particle.style.setProperty('--delay', `${Math.random() * 0.5}s`);
    particle.style.setProperty('--drift', `${(Math.random() - 0.5) * 60}px`);
    particle.style.left = `${Math.random() * 100}%`;
    particle.style.bottom = '0';
    container.appendChild(particle);

    // 动画结束后移除
    setTimeout(() => particle.remove(), (0.5 + config.maxDuration) * 1000 + 500);
  }
}

Impact Splash Ring

冲击水花环

css
.splash-ring {
  position: absolute;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.6);
  background: transparent;
  animation: splash-expand 0.8s ease-out forwards;
}

@keyframes splash-expand {
  0% {
    width: 10px;
    height: 10px;
    opacity: 1;
    transform: translate(-50%, -50%) rotateX(70deg);
  }
  100% {
    width: 150px;
    height: 150px;
    opacity: 0;
    transform: translate(-50%, -50%) rotateX(70deg);
  }
}

css
.splash-ring {
  position: absolute;
  border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, 0.6);
  background: transparent;
  animation: splash-expand 0.8s ease-out forwards;
}

@keyframes splash-expand {
  0% {
    width: 10px;
    height: 10px;
    opacity: 1;
    transform: translate(-50%, -50%) rotateX(70deg);
  }
  100% {
    width: 150px;
    height: 150px;
    opacity: 0;
    transform: translate(-50%, -50%) rotateX(70deg);
  }
}

SECTION K: BEACH WASH & FOAM

K部分:海岸冲刷与泡沫

Shore Wash Animation

海岸冲刷动画

svg
<svg class="beach-wave" viewBox="0 0 1440 200" preserveAspectRatio="none">
  <defs>
    <linearGradient id="foam-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" stop-color="rgba(255,255,255,0.9)" />
      <stop offset="30%" stop-color="rgba(200,230,255,0.6)" />
      <stop offset="100%" stop-color="rgba(56,189,248,0.4)" />
    </linearGradient>

    <filter id="foam-texture">
      <feTurbulence type="turbulence" baseFrequency="0.02 0.05" numOctaves="3" />
      <feDisplacementMap in="SourceGraphic" scale="5" />
    </filter>
  </defs>

  <path
    class="wave-foam"
    fill="url(#foam-gradient)"
    filter="url(#foam-texture)"
  >
    <animate
      attributeName="d"
      dur="4s"
      repeatCount="indefinite"
      values="
        M0,100 Q360,50 720,100 T1440,100 L1440,200 L0,200 Z;
        M0,80 Q360,130 720,80 T1440,80 L1440,200 L0,200 Z;
        M0,100 Q360,50 720,100 T1440,100 L1440,200 L0,200 Z
      "
    />
  </path>
</svg>
css
.beach-container {
  position: relative;
  height: 300px;
  overflow: hidden;
}

.wet-sand {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100px;
  background: linear-gradient(
    to top,
    #c2b280 0%,
    #d4c896 50%,
    #e6dbb0 100%
  );
}

.wet-sand::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(56, 189, 248, 0.2);
  animation: wet-recede 4s ease-in-out infinite;
}

@keyframes wet-recede {
  0%, 100% {
    clip-path: polygon(0 0, 100% 0, 100% 80%, 0 60%);
  }
  50% {
    clip-path: polygon(0 30%, 100% 50%, 100% 100%, 0 100%);
  }
}
svg
<svg class="beach-wave" viewBox="0 0 1440 200" preserveAspectRatio="none">
  <defs>
    <linearGradient id="foam-gradient" x1="0%" y1="0%" x2="0%" y2="100%">
      <stop offset="0%" stop-color="rgba(255,255,255,0.9)" />
      <stop offset="30%" stop-color="rgba(200,230,255,0.6)" />
      <stop offset="100%" stop-color="rgba(56,189,248,0.4)" />
    </linearGradient>

    <filter id="foam-texture">
      <feTurbulence type="turbulence" baseFrequency="0.02 0.05" numOctaves="3" />
      <feDisplacementMap in="SourceGraphic" scale="5" />
    </filter>
  </defs>

  <path
    class="wave-foam"
    fill="url(#foam-gradient)"
    filter="url(#foam-texture)"
  >
    <animate
      attributeName="d"
      dur="4s"
      repeatCount="indefinite"
      values="
        M0,100 Q360,50 720,100 T1440,100 L1440,200 L0,200 Z;
        M0,80 Q360,130 720,80 T1440,80 L1440,200 L0,200 Z;
        M0,100 Q360,50 720,100 T1440,100 L1440,200 L0,200 Z
      "
    />
  </path>
</svg>
css
.beach-container {
  position: relative;
  height: 300px;
  overflow: hidden;
}

.wet-sand {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  height: 100px;
  background: linear-gradient(
    to top,
    #c2b280 0%,
    #d4c896 50%,
    #e6dbb0 100%
  );
}

.wet-sand::before {
  content: '';
  position: absolute;
  inset: 0;
  background: rgba(56, 189, 248, 0.2);
  animation: wet-recede 4s ease-in-out infinite;
}

@keyframes wet-recede {
  0%, 100% {
    clip-path: polygon(0 0, 100% 0, 100% 80%, 0 60%);
  }
  50% {
    clip-path: polygon(0 30%, 100% 50%, 100% 100%, 0 100%);
  }
}

Foam Bubble Details

泡沫气泡细节

css
.foam-bubbles {
  position: absolute;
  width: 100%;
  height: 30px;
  bottom: 60px;
}

.foam-bubble {
  position: absolute;
  width: var(--size, 8px);
  height: var(--size, 8px);
  border-radius: 50%;
  background: radial-gradient(
    circle at 30% 30%,
    rgba(255, 255, 255, 0.9) 0%,
    rgba(200, 230, 255, 0.5) 50%,
    transparent 100%
  );
  animation: bubble-pop var(--duration, 2s) ease-out infinite;
  animation-delay: var(--delay, 0s);
}

@keyframes bubble-pop {
  0% {
    transform: scale(1);
    opacity: 0.8;
  }
  80% {
    transform: scale(1.1);
    opacity: 0.6;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}
css
.foam-bubbles {
  position: absolute;
  width: 100%;
  height: 30px;
  bottom: 60px;
}

.foam-bubble {
  position: absolute;
  width: var(--size, 8px);
  height: var(--size, 8px);
  border-radius: 50%;
  background: radial-gradient(
    circle at 30% 30%,
    rgba(255, 255, 255, 0.9) 0%,
    rgba(200, 230, 255, 0.5) 50%,
    transparent 100%
  );
  animation: bubble-pop var(--duration, 2s) ease-out infinite;
  animation-delay: var(--delay, 0s);
}

@keyframes bubble-pop {
  0% {
    transform: scale(1);
    opacity: 0.8;
  }
  80% {
    transform: scale(1.1);
    opacity: 0.6;
  }
  100% {
    transform: scale(0);
    opacity: 0;
  }
}

Receding Wave Trail

退浪痕迹

css
.wave-trail {
  position: absolute;
  bottom: 60px;
  left: 0;
  right: 0;
  height: 5px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.6) 10%,
    rgba(255, 255, 255, 0.8) 50%,
    rgba(255, 255, 255, 0.6) 90%,
    transparent 100%
  );
  animation: trail-recede 4s ease-in-out infinite;
}

@keyframes trail-recede {
  0% {
    transform: translateY(0) scaleX(1);
    opacity: 0.8;
  }
  50% {
    transform: translateY(-30px) scaleX(0.95);
    opacity: 0.4;
  }
  100% {
    transform: translateY(0) scaleX(1);
    opacity: 0.8;
  }
}

css
.wave-trail {
  position: absolute;
  bottom: 60px;
  left: 0;
  right: 0;
  height: 5px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    rgba(255, 255, 255, 0.6) 10%,
    rgba(255, 255, 255, 0.8) 50%,
    rgba(255, 255, 255, 0.6) 90%,
    transparent 100%
  );
  animation: trail-recede 4s ease-in-out infinite;
}

@keyframes trail-recede {
  0% {
    transform: translateY(0) scaleX(1);
    opacity: 0.8;
  }
  50% {
    transform: translateY(-30px) scaleX(0.95);
    opacity: 0.4;
  }
  100% {
    transform: translateY(0) scaleX(1);
    opacity: 0.8;
  }
}

SECTION L: PERFORMANCE OPTIMIZATION

L部分:性能优化

Performance Tiers

性能层级

css
/* Tier 1: Ultra Performance (CSS-only) */
@media (prefers-reduced-motion: reduce) {
  .weather-effect {
    animation: none !important;
    filter: none !important;
  }
}

/* Tier 2: High Performance (static filters) */
.weather-effect--performance {
  filter: url(#static-filter);
  animation-play-state: paused;
}

/* Tier 3: Full Effects */
.weather-effect--full {
  filter: url(#animated-filter);
  animation-play-state: running;
}
css
/* 层级1:极致性能(纯CSS) */
@media (prefers-reduced-motion: reduce) {
  .weather-effect {
    animation: none !important;
    filter: none !important;
  }
}

/* 层级2:高性能(静态滤镜) */
.weather-effect--performance {
  filter: url(#static-filter);
  animation-play-state: paused;
}

/* 层级3:完整特效 */
.weather-effect--full {
  filter: url(#animated-filter);
  animation-play-state: running;
}

GPU Acceleration

GPU加速

css
.weather-layer {
  /* Force GPU compositing */
  will-change: transform, opacity;
  transform: translateZ(0);
  backface-visibility: hidden;

  /* Avoid triggering repaints */
  contain: layout paint;
}

/* Avoid animating these properties */
.weather-layer {
  /* BAD: causes repaints */
  /* animation: filter-change 10s; */

  /* GOOD: GPU-accelerated */
  animation: transform-change 10s;
}
css
.weather-layer {
  /* 强制GPU合成 */
  will-change: transform, opacity;
  transform: translateZ(0);
  backface-visibility: hidden;

  /* 避免触发重绘 */
  contain: layout paint;
}

/* 避免动画这些属性 */
.weather-layer {
  /* 错误:会触发重绘 */
  /* animation: filter-change 10s; */

  /* 正确:GPU加速 */
  animation: transform-change 10s;
}

Intersection Observer for Off-Screen

交叉观察器处理屏幕外元素

javascript
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    const effect = entry.target;
    if (entry.isIntersecting) {
      effect.classList.add('weather-effect--active');
    } else {
      effect.classList.remove('weather-effect--active');
    }
  });
}, { threshold: 0.1 });

document.querySelectorAll('.weather-effect').forEach(el => observer.observe(el));
javascript
const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    const effect = entry.target;
    if (entry.isIntersecting) {
      effect.classList.add('weather-effect--active');
    } else {
      effect.classList.remove('weather-effect--active');
    }
  });
}, { threshold: 0.1 });

document.querySelectorAll('.weather-effect').forEach(el => observer.observe(el));

Mobile Optimization

移动端优化

css
@media (max-width: 768px) {
  /* Reduce layer count on mobile */
  .cloud-back,
  .fog-back {
    display: none;
  }

  /* Simplify filters */
  .weather-filter {
    filter: blur(var(--blur)) opacity(0.5);
  }

  /* Reduce particle count */
  .rain-container {
    --drop-count: 50;
  }
}

css
@media (max-width: 768px) {
  /* 移动端减少图层数量 */
  .cloud-back,
  .fog-back {
    display: none;
  }

  /* 简化滤镜 */
  .weather-filter {
    filter: blur(var(--blur)) opacity(0.5);
  }

  /* 减少粒子数量 */
  .rain-container {
    --drop-count: 50;
  }
}

SECTION M: REACT INTEGRATION

M部分:React集成

Weather Effect Provider

天气特效提供者

tsx
import React, { createContext, useContext, useState, useEffect } from 'react';

type WeatherType =
  | 'clear'
  | 'cloudy'
  | 'rainy'
  | 'stormy'
  | 'foggy'
  | 'snowy'
  | 'aurora';

type TimeOfDay = 'dawn' | 'morning' | 'noon' | 'afternoon' | 'dusk' | 'night';

interface WeatherContextType {
  weather: WeatherType;
  timeOfDay: TimeOfDay;
  intensity: number; // 0-1
  setWeather: (w: WeatherType) => void;
  setTimeOfDay: (t: TimeOfDay) => void;
  setIntensity: (i: number) => void;
}

const WeatherContext = createContext<WeatherContextType | null>(null);

export function WeatherProvider({ children }: { children: React.ReactNode }) {
  const [weather, setWeather] = useState<WeatherType>('clear');
  const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('noon');
  const [intensity, setIntensity] = useState(0.5);

  // Auto-detect time of day
  useEffect(() => {
    const hour = new Date().getHours();
    if (hour >= 5 && hour < 7) setTimeOfDay('dawn');
    else if (hour >= 7 && hour < 12) setTimeOfDay('morning');
    else if (hour >= 12 && hour < 14) setTimeOfDay('noon');
    else if (hour >= 14 && hour < 17) setTimeOfDay('afternoon');
    else if (hour >= 17 && hour < 20) setTimeOfDay('dusk');
    else setTimeOfDay('night');
  }, []);

  return (
    <WeatherContext.Provider value={{
      weather, timeOfDay, intensity,
      setWeather, setTimeOfDay, setIntensity
    }}>
      {children}
    </WeatherContext.Provider>
  );
}

export const useWeather = () => {
  const context = useContext(WeatherContext);
  if (!context) throw new Error('useWeather must be used within WeatherProvider');
  return context;
};
tsx
import React, { createContext, useContext, useState, useEffect } from 'react';

type WeatherType =
  | 'clear'
  | 'cloudy'
  | 'rainy'
  | 'stormy'
  | 'foggy'
  | 'snowy'
  | 'aurora';

type TimeOfDay = 'dawn' | 'morning' | 'noon' | 'afternoon' | 'dusk' | 'night';

interface WeatherContextType {
  weather: WeatherType;
  timeOfDay: TimeOfDay;
  intensity: number; // 0-1
  setWeather: (w: WeatherType) => void;
  setTimeOfDay: (t: TimeOfDay) => void;
  setIntensity: (i: number) => void;
}

const WeatherContext = createContext<WeatherContextType | null>(null);

export function WeatherProvider({ children }: { children: React.ReactNode }) {
  const [weather, setWeather] = useState<WeatherType>('clear');
  const [timeOfDay, setTimeOfDay] = useState<TimeOfDay>('noon');
  const [intensity, setIntensity] = useState(0.5);

  // 自动检测时段
  useEffect(() => {
    const hour = new Date().getHours();
    if (hour >= 5 && hour < 7) setTimeOfDay('dawn');
    else if (hour >= 7 && hour < 12) setTimeOfDay('morning');
    else if (hour >= 12 && hour < 14) setTimeOfDay('noon');
    else if (hour >= 14 && hour < 17) setTimeOfDay('afternoon');
    else if (hour >= 17 && hour < 20) setTimeOfDay('dusk');
    else setTimeOfDay('night');
  }, []);

  return (
    <WeatherContext.Provider value={{
      weather, timeOfDay, intensity,
      setWeather, setTimeOfDay, setIntensity
    }}>
      {children}
    </WeatherContext.Provider>
  );
}

export const useWeather = () => {
  const context = useContext(WeatherContext);
  if (!context) throw new Error('useWeather must be used within WeatherProvider');
  return context;
};

Atmospheric Canvas Component

大气画布组件

tsx
import React from 'react';
import { useWeather } from './WeatherProvider';
import { CloudLayer } from './CloudLayer';
import { RainEffect } from './RainEffect';
import { LightningEffect } from './LightningEffect';
import { FogLayer } from './FogLayer';
import { AuroraEffect } from './AuroraEffect';
import { SkyGradient } from './SkyGradient';

export function AtmosphericCanvas() {
  const { weather, timeOfDay, intensity } = useWeather();

  return (
    <div className="atmospheric-canvas">
      {/* SVG Filters */}
      <svg width="0" height="0" aria-hidden="true">
        <defs>
          <filter id="cloud-filter">...</filter>
          <filter id="fog-filter">...</filter>
          <filter id="wave-filter">...</filter>
        </defs>
      </svg>

      {/* Sky base */}
      <SkyGradient timeOfDay={timeOfDay} />

      {/* Weather layers */}
      {(weather === 'cloudy' || weather === 'rainy' || weather === 'stormy') && (
        <CloudLayer variant={weather === 'stormy' ? 'storm' : 'cumulus'} />
      )}

      {weather === 'foggy' && <FogLayer intensity={intensity} />}

      {weather === 'aurora' && <AuroraEffect intensity={intensity} />}

      {(weather === 'rainy' || weather === 'stormy') && (
        <RainEffect intensity={weather === 'stormy' ? 1 : intensity} />
      )}

      {weather === 'stormy' && <LightningEffect frequency={intensity} />}
    </div>
  );
}
tsx
import React from 'react';
import { useWeather } from './WeatherProvider';
import { CloudLayer } from './CloudLayer';
import { RainEffect } from './RainEffect';
import { LightningEffect } from './LightningEffect';
import { FogLayer } from './FogLayer';
import { AuroraEffect } from './AuroraEffect';
import { SkyGradient } from './SkyGradient';

export function AtmosphericCanvas() {
  const { weather, timeOfDay, intensity } = useWeather();

  return (
    <div className="atmospheric-canvas">
      {/* SVG Filters */}
      <svg width="0" height="0" aria-hidden="true">
        <defs>
          <filter id="cloud-filter">...</filter>
          <filter id="fog-filter">...</filter>
          <filter id="wave-filter">...</filter>
        </defs>
      </svg>

      {/* 天空底色 */}
      <SkyGradient timeOfDay={timeOfDay} />

      {/* 天气图层 */}
      {(weather === 'cloudy' || weather === 'rainy' || weather === 'stormy') && (
        <CloudLayer variant={weather === 'stormy' ? 'storm' : 'cumulus'} />
      )}

      {weather === 'foggy' && <FogLayer intensity={intensity} />}

      {weather === 'aurora' && <AuroraEffect intensity={intensity} />}

      {(weather === 'rainy' || weather === 'stormy') && (
        <RainEffect intensity={weather === 'stormy' ? 1 : intensity} />
      )}

      {weather === 'stormy' && <LightningEffect frequency={intensity} />}
    </div>
  );
}

Individual Effect Components

独立特效组件

tsx
// CloudLayer.tsx
interface CloudLayerProps {
  variant: 'cumulus' | 'cirrus' | 'stratus' | 'storm';
  opacity?: number;
}

export function CloudLayer({ variant, opacity = 0.7 }: CloudLayerProps) {
  const configs = {
    cumulus: { baseFrequency: 0.008, blur: 4, layers: 3 },
    cirrus: { baseFrequency: 0.003, blur: 2, layers: 2 },
    stratus: { baseFrequency: 0.015, blur: 6, layers: 2 },
    storm: { baseFrequency: 0.006, blur: 3, layers: 4 }
  };

  const config = configs[variant];

  return (
    <div className="cloud-system" style={{ '--opacity': opacity } as React.CSSProperties}>
      {Array.from({ length: config.layers }, (_, i) => (
        <div
          key={i}
          className={`cloud-layer cloud-layer-${i}`}
          style={{
            '--layer-index': i,
            '--animation-duration': `${50 + i * 30}s`
          } as React.CSSProperties}
        />
      ))}
    </div>
  );
}

tsx
// CloudLayer.tsx
interface CloudLayerProps {
  variant: 'cumulus' | 'cirrus' | 'stratus' | 'storm';
  opacity?: number;
}

export function CloudLayer({ variant, opacity = 0.7 }: CloudLayerProps) {
  const configs = {
    cumulus: { baseFrequency: 0.008, blur: 4, layers: 3 },
    cirrus: { baseFrequency: 0.003, blur: 2, layers: 2 },
    stratus: { baseFrequency: 0.015, blur: 6, layers: 2 },
    storm: { baseFrequency: 0.006, blur: 3, layers: 4 }
  };

  const config = configs[variant];

  return (
    <div className="cloud-system" style={{ '--opacity': opacity } as React.CSSProperties}>
      {Array.from({ length: config.layers }, (_, i) => (
        <div
          key={i}
          className={`cloud-layer cloud-layer-${i}`}
          style={{
            '--layer-index': i,
            '--animation-duration': `${50 + i * 30}s`
          } as React.CSSProperties}
        />
      ))}
    </div>
  );
}

SECTION N: TAILWIND INTEGRATION

N部分:Tailwind集成

Custom Tailwind Utilities

自定义Tailwind工具类

javascript
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      animation: {
        'drift': 'drift 60s linear infinite',
        'drift-slow': 'drift 120s linear infinite',
        'drift-fast': 'drift 30s linear infinite',
        'wave': 'wave 10s ease-in-out infinite',
        'rain-fall': 'rain-fall 0.8s linear infinite',
        'lightning': 'lightning-flash 0.5s ease-out',
        'aurora': 'aurora-wave 15s ease-in-out infinite',
        'fog-breathe': 'fog-breathe 8s ease-in-out infinite',
      },
      keyframes: {
        drift: {
          '0%': { transform: 'translateX(-10%)' },
          '100%': { transform: 'translateX(10%)' },
        },
        wave: {
          '0%, 100%': { transform: 'translateY(0)' },
          '50%': { transform: 'translateY(-10px)' },
        },
        'rain-fall': {
          '0%': { transform: 'translateY(-100vh)' },
          '100%': { transform: 'translateY(100vh)' },
        },
        'lightning-flash': {
          '0%': { opacity: '0' },
          '10%': { opacity: '1' },
          '20%': { opacity: '0.5' },
          '30%': { opacity: '1' },
          '100%': { opacity: '0' },
        },
        'aurora-wave': {
          '0%, 100%': { transform: 'translateX(-20%) skewX(-5deg)', opacity: '0.4' },
          '50%': { transform: 'translateX(0%) skewX(5deg)', opacity: '0.7' },
        },
        'fog-breathe': {
          '0%, 100%': { opacity: '0.5', transform: 'scaleY(1)' },
          '50%': { opacity: '0.7', transform: 'scaleY(1.1)' },
        },
      },
      backdropBlur: {
        'fog': '20px',
        'mist': '10px',
      },
    },
  },
  plugins: [
    function({ addUtilities }) {
      addUtilities({
        '.filter-cloud': {
          filter: 'url(#cloud-filter)',
        },
        '.filter-fog': {
          filter: 'url(#fog-filter)',
        },
        '.filter-wave': {
          filter: 'url(#wave-filter)',
        },
        '.mix-screen': {
          mixBlendMode: 'screen',
        },
        '.mix-overlay': {
          mixBlendMode: 'overlay',
        },
      });
    },
  ],
};
javascript
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      animation: {
        'drift': 'drift 60s linear infinite',
        'drift-slow': 'drift 120s linear infinite',
        'drift-fast': 'drift 30s linear infinite',
        'wave': 'wave 10s ease-in-out infinite',
        'rain-fall': 'rain-fall 0.8s linear infinite',
        'lightning': 'lightning-flash 0.5s ease-out',
        'aurora': 'aurora-wave 15s ease-in-out infinite',
        'fog-breathe': 'fog-breathe 8s ease-in-out infinite',
      },
      keyframes: {
        drift: {
          '0%': { transform: 'translateX(-10%)' },
          '100%': { transform: 'translateX(10%)' },
        },
        wave: {
          '0%, 100%': { transform: 'translateY(0)' },
          '50%': { transform: 'translateY(-10px)' },
        },
        'rain-fall': {
          '0%': { transform: 'translateY(-100vh)' },
          '100%': { transform: 'translateY(100vh)' },
        },
        'lightning-flash': {
          '0%': { opacity: '0' },
          '10%': { opacity: '1' },
          '20%': { opacity: '0.5' },
          '30%': { opacity: '1' },
          '100%': { opacity: '0' },
        },
        'aurora-wave': {
          '0%, 100%': { transform: 'translateX(-20%) skewX(-5deg)', opacity: '0.4' },
          '50%': { transform: 'translateX(0%) skewX(5deg)', opacity: '0.7' },
        },
        'fog-breathe': {
          '0%, 100%': { opacity: '0.5', transform: 'scaleY(1)' },
          '50%': { opacity: '0.7', transform: 'scaleY(1.1)' },
        },
      },
      backdropBlur: {
        'fog': '20px',
        'mist': '10px',
      },
    },
  },
  plugins: [
    function({ addUtilities }) {
      addUtilities({
        '.filter-cloud': {
          filter: 'url(#cloud-filter)',
        },
        '.filter-fog': {
          filter: 'url(#fog-filter)',
        },
        '.filter-wave': {
          filter: 'url(#wave-filter)',
        },
        '.mix-screen': {
          mixBlendMode: 'screen',
        },
        '.mix-overlay': {
          mixBlendMode: 'overlay',
        },
      });
    },
  ],
};

Tailwind Component Classes

Tailwind组件类示例

html
<!-- Cloud layer -->
<div class="absolute inset-0 opacity-50 filter-cloud animate-drift-slow"></div>

<!-- Rain container -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
  <div class="w-0.5 h-5 bg-gradient-to-b from-transparent via-sky-200/50 to-sky-300/80 rounded-b animate-rain-fall"></div>
</div>

<!-- Fog overlay -->
<div class="absolute inset-0 bg-white/30 backdrop-blur-fog filter-fog animate-fog-breathe"></div>

<!-- Aurora band -->
<div class="absolute top-1/4 -left-1/2 w-[200%] h-2/5 opacity-60 mix-screen blur-3xl animate-aurora bg-gradient-to-r from-transparent via-emerald-400/40 to-transparent"></div>

html
<!-- 云朵图层 -->
<div class="absolute inset-0 opacity-50 filter-cloud animate-drift-slow"></div>

<!-- 降雨容器 -->
<div class="absolute inset-0 overflow-hidden pointer-events-none">
  <div class="w-0.5 h-5 bg-gradient-to-b from-transparent via-sky-200/50 to-sky-300/80 rounded-b animate-rain-fall"></div>
</div>

<!-- 雾霭覆盖层 -->
<div class="absolute inset-0 bg-white/30 backdrop-blur-fog filter-fog animate-fog-breathe"></div>

<!-- 极光带 -->
<div class="absolute top-1/4 -left-1/2 w-[200%] h-2/5 opacity-60 mix-screen blur-3xl animate-aurora bg-gradient-to-r from-transparent via-emerald-400/40 to-transparent"></div>

Quick Reference Card

快速参考卡片

Effect Selection Matrix

特效选择矩阵

EffectBest ForComplexityPerformance
CloudsHero sections, headersMediumHigh
WavesFooters, section dividersMediumHigh
LightningDramatic moments, gamingLowVery High
RainMood, atmosphereMediumMedium
FogMystery, depthLowHigh
AuroraNight scenes, magicalHighMedium
God raysDivine, cinematicLowHigh
Lens flareRealistic, photographyMediumHigh
Ocean sprayBeach, actionHighLow
Beach washCoastal, calmMediumMedium
Twilight skyTime indicationLowVery High
特效适用场景复杂度性能
云朵英雄区、页眉中等
波浪页脚、区域分隔中等
闪电戏剧性场景、游戏极高
降雨氛围营造中等中等
雾霭神秘感、深度
极光夜景、魔法风格中等
耶稣光神圣感、电影风格
镜头光晕写实感、摄影风格中等
海浪喷雾海滩、动作场景
海岸冲刷海滨、平静场景中等中等
黄昏天空时段指示极高

Common Combinations

常见组合

SceneEffectsNotes
Dramatic stormStorm clouds + Rain + LightningStagger lightning timing
Peaceful beachLight clouds + Beach wash + God raysSlow animations
Foggy morningFog + Ground mist + Soft cloudsReduce saturation
Northern nightAurora + Stars + Light fogDark background essential
Cinematic momentGod rays + Lens flare + Light hazeDon't overdo flares
场景特效组合注意事项
风暴场景风暴云 + 降雨 + 闪电错开闪电触发时机
宁静海滩轻量云朵 + 海岸冲刷 + 耶稣光慢速动画
雾霭清晨雾霭 + 贴地薄雾 + 柔和云朵降低饱和度
北极夜景极光 + 星空 + 轻雾深色背景必备
电影时刻耶稣光 + 镜头光晕 + 轻度薄雾避免过度使用光晕

Performance Budget

性能预算

DeviceMax LayersMax ParticlesFilter Complexity
Desktop5-7200Full
Tablet3-5100Simplified
Mobile2-350Minimal

设备最大图层数最大粒子数滤镜复杂度
桌面端5-7200完整
平板3-5100简化
移动端2-350极简

Resources & References

资源与参考

Tutorials Referenced

参考教程

Tools

工具

Code Collections

代码集合

Version History

版本历史

  • v1.0.0 (2026-01-25): Merged from web-cloud-designer + web-wave-designer, added lightning, rain, fog, twilight, aurora, god rays, lens flare, ocean spray, beach wash effects

Remember: Stylized weather effects are about restraint and layering. One well-crafted effect beats five mediocre ones. When in doubt, reduce intensity and increase subtlety.
  • v1.0.0 (2026-01-25): 合并自web-cloud-designer + web-wave-designer,新增闪电、降雨、雾霭、黄昏、极光、耶稣光、镜头光晕、海浪喷雾、海岸冲刷特效

记住:风格化天气特效的核心是克制与分层。一个精心设计的特效胜过五个平庸的效果。如有疑问,降低强度,增加细腻度。