mcpField
W
web-cloud-designer

web-cloud-designer

github.com/curiositechデザイン・UI257173 回インストール2 日前に更新
リポジトリ

web-cloud-designer について

SVGフィルター、CSSアニメーション、レイヤー効果で雲のビジュアルを作るウェブ開発者向けのデザインスキルです。雲の表現、視差効果、性能上の配慮を扱い、背景や天気画面、ローディング表示に使えます。

主な機能

  1. 01SVGフィルターによる雲形状の生成
  2. 02レイヤーで奥行きと視差を構成
  3. 03CSSで雲の移動をアニメーション
  4. 04ReactとVueの実装テンプレート
  5. 05フィルターとアニメーションの性能最適化
  6. 06動きを減らす設定への対応

活用シーン

  1. 01雲のある空をヒーロー背景に作成
  2. 02天気テーマの画面や切り替え演出の設計
  3. 03視差のある雲のシーンの構築
  4. 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.json
references/
animation-patterns.md
svg-filter-deep-dive.md
color-and-lighting.md

詳細

Web Cloud Designer

SVG フィルター、CSS アニメーション、レイヤー化技法を使用して、Web アプリケーション向けのリアルで高パフォーマンスな雲のエフェクトを作成するエキスパートです。パフォーマンスを損なうことなくユーザー体験を向上させる、雰囲気のあるビジュアルを専門としています。

このスキルを使用する場面

使用する場面:

  • リアルな雲の背景やスカイボックス
  • 天候をテーマにした UI 要素やトランジション
  • 奥行きのある視差効果付きの雲のシーン
  • アニメーション付きの大気エフェクト
  • スタイライズされた雲や漫画風の雲のデザイン
  • 空をテーマにしたヒーローセクションの背景
  • 雲のアニメーションを使ったローディング状態
  • ゲーム風の雲のレイヤー

使用しない場面:

  • 3D ボリューム雲のレンダリング → WebGL/Three.js を使用
  • 実際の雲の写真の加工 → 画像編集を使用
  • 気象データの統合 → 天気 API のスキルを使用
  • 雲の形がないシンプルなグラデーションの空
  • 雲を含む動画の背景

コア技法のリファレンス

SVG フィルターパイプライン

基本となる雲のエフェクトでは、次のフィルターチェーンを使用します。

Source -> feTurbulence -> feDisplacementMap -> feGaussianBlur -> feDiffuseLighting -> Composite
1. feTurbulence - 基礎

雲の形を作るパーリンノイズを生成します。

<feTurbulence
  type="fractalNoise"      
  baseFrequency="0.01"     
  numOctaves="4"           
  seed="42"                
  result="noise"
/>
パラメーター範囲効果
baseFrequency0.005-0.02雲の形のスケールです。0.005 = 巨大な積雲、0.02 = 小さな筋状の雲
numOctaves3-5ディテールのレイヤーです。3 = なめらか、5 = 詳細です。5 を超えると CPU の無駄になります
seed0-999999形状のバリエーションです。多様性を出すには、baseFrequency ではなくこちらを変更してください
typefractalNoise雲には必ず fractalNoise を使用してください(turbulence は炎や水向けです)
2. feDisplacementMap - 形状の変形

ノイズから有機的で膨らみのある雲の形を作ります。

<feDisplacementMap
  in="SourceGraphic"
  in2="noise"
  scale="80"               
  xChannelSelector="R"
  yChannelSelector="G"
/>
スケール値効果
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(2 つの値)を使うと、方向性のある細長い筋状の雲になります。

層雲(平坦な層状の雲)
<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.490-120s1.3-1.5x5-8
中景0.5-0.750-80s1.0x3-5
前景(近景)0.8-1.030-50s0.7-0.9x1-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 のみの box-shadow の雲

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;
}

パフォーマンスの最適化

重要なルール
  1. numOctaves は 5 以下にする - 5 を超えると、視覚的な改善は小さくなる一方で CPU コストは指数関数的に増加します
  2. 変形より前にぼかす - ぼかしを後に適用する場合と比べて 40% 効率的です
  3. フィルタープロパティのアニメーションを避ける - 代わりに CSS トランスフォームを使用してください
  4. バリエーションには seed を使用する - baseFrequency を変更する場合と違い、パフォーマンスコストがかかりません
  5. will-change: transform - アニメーションする要素にのみ指定し、静止状態になったら削除してください
  6. フィルター定義をまとめる - <defs> ブロックを 1 つだけ作成し、ID を参照してください
パフォーマンスティア
ティア技法FPS の目標用途
UltraCSS box-shadow のみ60fpsモバイル、低スペック端末
HighSVG filter、アニメーションなし60fps静的な背景
MediumSVG filter + CSS transform アニメーション45-60fpsさりげない動き
LowSVG 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 Clouds」(ビルボード技法)
  • Nephele Cloud Generator ツール
  • MDN:SVG フィルタープリミティブのドキュメント

雲は、空にも質感があることを思い出させてくれる自然からのメッセージです。

コメント