GODRICH

ai ランディングページ 光るオーブ デザインキット、セクション9選

ai ランディングページの光るオーブとは、台になる背景を単色のまま置いて、画面の中で光るものを丸い球ひとつに絞る作り方です。グラデーション背景なしでもAIらしく見えるこの手を、ヒーローからフッターまで貼って使える9つのセクションにまとめました。

AI製品のページは、この2年ほど画面いっぱいの虹色で「AIらしさ」を出してきました。同じ表現が増えすぎた結果、今はどれも同じ顔に見えます。このキットが取るのは反対の手です。台を#17141aのインク1色まで落として、光の予算を球ひとつに集めます。使う色数は変わりませんが、光る場所がひとつしかないぶん、その一点が製品の顔になります。まずは下のワンページを上から下までたどって、光っている点がいくつあるか数えてみてください。

ページを新しいタブで開く

このワンページを9つに切り分けて、下のグリッドに並べました。並びは人気順ではなく、訪問者が出会う順です。最初の画面から上部バー、機能の紹介、料金、利用者の声、最後の一押し、そしてフッターへ。9つ目だけは場所ではなく、どのセクションにも顔を出すボタンと入力欄です。球の色も同じ順に、空色#6ec8ffから青#2f6df6、ライラック#b9a0ffへと3段で降りていきます。

自動再生 · タイルを押すとその項目へ · すべて1つのzip

01浮かぶオーブヒーロー

濃いインクの台の上で、radial-gradientを4枚重ねただけの球が、2秒かけて上下14pxの幅をゆっくり往復します。写真もfilterも使っていないので、色の行を差し替えるだけで自社のブランドカラーの球になります。撮った24コマを隣どうしで比べた23回すべてで画素が動き、変化した面積は累計9.73%、変化の強さは平均43.7でした。

radial-gradienttranslateYscalearia-hidden
.ho__orb {
  position: relative; z-index: 1; width: 104px; height: 104px; border-radius: 50%;
  // 上からハイライト・空色の光・ライラックの映り込み・本体の4枚
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, .92), rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 28% 66%, rgba(110, 200, 255, .9), rgba(110, 200, 255, 0) 58%),
    radial-gradient(circle at 74% 72%, rgba(185, 160, 255, .8), rgba(185, 160, 255, 0) 56%),
    radial-gradient(circle at 50% 50%, rgba(47, 109, 246, .95) 10%, rgba(23, 20, 26, .96) 92%);
  animation-name: hoFloat; animation-duration: $duration; animation-timing-function: $easing;
  animation-iteration-count: infinite;
}
// 0% と 100% が同じ値なので、ループのつなぎ目が出ない
@keyframes hoFloat {
  0%, 100% { transform: translateY(7px); }
  50% { transform: translateY(-7px); }
}
@keyframes hoPulse {
  0%, 100% { transform: scale(.82); opacity: .5; }
  50% { transform: scale(1); opacity: .9; }
}

02すべるオーブドットナビ

メニュー5項目の下を、8pxの発光ドットがアクティブ項目までtranslateXですべっていきます。--p1から--p5の5か所は480×300で実測した初期値にすぎず、読み込み時と画面幅が変わるたびにoffsetLeftoffsetWidthで実際の座標を読み直して上書きするので、ラベルの幅が違う日本語でも点はラベルの中央に立ちます。動くのは点だけなので、変化した面積は累計2.08%、動きが出たのは23回の比較のうち15回でした。

translateXtransitionaria-current
.nv__dot {
  // 5か所は推測ではなく Playwright の getBoundingClientRect 実測値 (480×300 レンダー, 2026-09-12)
  --p1: 1.5px; --p2: 38px; --p3: 80px; --p4: 122px; --p5: 164px;
  position: absolute; left: 0; bottom: 0; width: 8px; height: 8px; border-radius: 50%;
  background: radial-gradient(circle at 38% 32%, rgba(255, 255, 255, .95), rgba(110, 200, 255, .95) 58%, rgba(47, 109, 246, .9) 100%);
  box-shadow: 0 0 12px 4px rgba(110, 200, 255, .45);
  transform: translateX(var(--p1));
  transition: transform $duration $easing;
}
// プレビュー用のループ。1 → 3 → 5 → 1 と3か所を回る
@keyframes nvGlide {
  0%, 8% { transform: translateX(var(--p1)); }
  24%, 34% { transform: translateX(var(--p3)); }
  50%, 62% { transform: translateX(var(--p5)); }
  86%, 100% { transform: translateX(var(--p1)); }
}

03きらめき応答カードグリッド

濃いカード4枚に28pxの球が乗り、ホバーで球が自分の中心から1.35倍にふくらみ、カードが2px浮いて影が深くなります。カーソルを追いかけるスポットライトは使いません。プレビューでは4枚が120msずつずれて同じ反応を1周し、変化した面積は累計10.70%、強さは平均48.7でした。

scaletranslateYbox-shadowgrid-template-columns
.cg__orb {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 50%; transform-origin: 50% 50%;
  background:
    radial-gradient(circle at 34% 28%, rgba(255, 255, 255, .95), rgba(255, 255, 255, 0) 46%),
    radial-gradient(circle at 66% 74%, rgba(185, 160, 255, .85), rgba(185, 160, 255, 0) 60%),
    radial-gradient(circle at 50% 50%, rgba(110, 200, 255, 1) 20%, rgba(47, 109, 246, .95) 96%);
  box-shadow: 0 0 10px rgba(110, 200, 255, .35);
  transition: transform $duration $easing;
}
// 実際に手を乗せたとき — カードが浮き、影が深まり、球がふくらむ
.cg__card:hover, .cg__card:focus-visible {
  transform: translateY(-2px); box-shadow: $shadow-raised;
}
.cg__card:hover .cg__orb, .cg__card:focus-visible .cg__orb { transform: scale(1.35); }

04順に目覚める機能リスト

6行のミニ球が、上から334msずつずれて明るくなり、また沈みます。明るい区間は1周2秒の16%(320ms)で終わるので、次の行が起きる334msと重ならず、どの瞬間も光っているのは1行だけです。23回の比較すべてで動きが出ましたが、変化した面積は累計4.37%と控えめでした。

animation-delayopacityradial-gradient
// 球の表面 — 左上のハイライト1枚と本体1枚。縁は台の側へ沈む
@mixin orbSkin($hue) {
  background:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, .92) 0%, rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 52% 54%, $hue 0%, rgba($hue, .45) 58%, rgba($subject-ink, .92) 100%);
}
// 2000ms ÷ 6行 = 334ms 刻み。6行目の 1667ms まで同じ形で並べる
.fl.is-demo .fl__row:nth-child(2) .fl__orb, .fl.is-demo .fl__row:nth-child(2) .fl__label { animation-delay: 334ms; }
.fl.is-demo .fl__row:nth-child(3) .fl__orb, .fl.is-demo .fl__row:nth-child(3) .fl__label { animation-delay: 667ms; }
@keyframes flWake {
  0%   { opacity: .32; transform: scale(.86); }
  5%   { opacity: 1;   transform: scale(1.18); }
  11%  { opacity: 1;   transform: scale(1.06); }
  16%  { opacity: .32; transform: scale(.86); }
  100% { opacity: .32; transform: scale(.86); }
}

05オーブバッジの料金プラン

白いペーパーの台に3プランを並べ、おすすめのカードの上にだけ28pxの球バッジが乗り、1秒周期で6px浮き沈みします。推すカードとの差は色の塗り替えではなく、枠の濃さと影の深さだけで付けます。動く面積は9つの中で最小の0.68%、強さも36.2にとどまり、価格表を読む邪魔をしません。

translateYbox-shadowborder-color
// 白い台なので、縁をインク側へ落として境界を立てる
.pr__orb {
  position: absolute; top: -14px; left: 50%; width: 28px; height: 28px; border-radius: 50%;
  background:
    radial-gradient(circle at 34% 26%, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, 0) 46%),
    radial-gradient(circle at 52% 56%, $color 0%, rgba($color, .9) 54%, rgba($subject-ink, .82) 100%);
  box-shadow: 0 4px 12px rgba($color, .45);
  transform: translateX(-50%);   // 横の中央合わせは固定、縦だけループが動かす
}
.pr__card--pick { border-color: rgba($subject-ink, .32); box-shadow: $shadow-raised; }
@keyframes prBob {
  0%   { transform: translateX(-50%) translateY(0); }
  50%  { transform: translateX(-50%) translateY(-6px); }
  100% { transform: translateX(-50%) translateY(0); }
}

06オーブアバターのレビュー

レビューカード3枚の上部に、青・ピンク・ミントと色だけを変えた球のアバターが乗ります。ホバーで球は1.18倍にふくらみ、不透明度が0.78から1へ上がって、カードが4px浮きます。3枚が667msずつずれて同じ反応を見せ、変化した面積は累計10.18%、強さは平均40.9でした。

radial-gradientscaletranslateY
// アバターの表面 — 色相だけ差し替えて話し手を見分ける
@mixin orbSkin($hue) {
  background:
    radial-gradient(circle at 32% 26%, rgba(255, 255, 255, .95) 0%, rgba(255, 255, 255, 0) 44%),
    radial-gradient(circle at 52% 56%, $hue 0%, rgba($hue, .5) 58%, rgba($subject-ink, .92) 100%);
  box-shadow: 0 0 12px rgba($hue, .42);   // 光の輪。球が暗くなると輪も一緒に沈む
}
.tm__orb--first  { @include orbSkin($subject-blue); }
.tm__orb--second { @include orbSkin($subject-pink); }
.tm__orb--third  { @include orbSkin($subject-mint); }
.tm__card:hover, .tm__card:active { transform: translateY(-4px); }
.tm__card:hover .tm__orb, .tm__card:active .tm__orb { opacity: 1; transform: scale(1.18); }

07漂うオーブCTA帯

オレンジの台に置いたインクの帯の中を、208pxの大きな球が2秒で左右に往復します。手前のボタンは光らないソリッドで、ホバーで1px浮いて影が深くなるだけです。球が帯のかなりの面を通るので、変化した面積は9つの中で最大の33.24%、ただし色が薄いぶん変化の強さは最小の25.5でした。

translateXradial-gradienttranslateY
.cb__orb {
  position: absolute; left: 50%; top: 50%;
  margin-left: -104px; margin-top: -104px;       // 自分の半分だけ引いて中央へ
  width: 208px; height: 208px; border-radius: 50%; z-index: 0; pointer-events: none;
  background: radial-gradient(circle at 50% 50%,
    rgba($color, .55) 0%,
    rgba($subject-blue, .40) 38%,
    rgba($subject-blue, 0) 70%);
  animation-name: orbDrift;
  animation-duration: $duration;
  animation-timing-function: ease-in-out;        // 往復は両端で緩まないと機械的に見える
  animation-iteration-count: infinite;
}
@keyframes orbDrift {
  0%   { transform: translateX(-34%); }
  50%  { transform: translateX(34%); }
  100% { transform: translateX(-34%); }
}

08軌道オーブフッター

フッター上部の区切り線を、20px・14px・24pxの3つのミニ球が横切ります。2つは2秒かけて渡り、残る1つはその半分の1秒で追い抜くうえ、負のanimation-delayで走り出す位置もずらしてあるので、どの瞬間を切り取っても線の上に必ず球がいます。変化の強さは9つの中で最も高い70.5で、23回の比較すべてに動きが出ました。

translateXanimation-delaygrid-template-columns
// 運び手の幅を軌道と同じにする — translateX の % がそのまま「軌道の何%」になる
.fo__beacon {
  position: absolute; left: 0; top: 50%; width: 100%; height: 0;
  animation-name: beaconCross;
  animation-timing-function: $easing;
  animation-iteration-count: infinite;
  animation-fill-mode: backwards;          // 遅延中の1コマ目が素の位置で光らないように
}
.fo__beacon--slow  { animation-duration: $duration; animation-delay: -400ms; }
.fo__beacon--fast  { animation-duration: $dur-loop * .5; animation-delay: -500ms; }
.fo__beacon--drift { animation-duration: $duration; animation-delay: -1200ms; }
@keyframes beaconCross {
  from { transform: translateX(-8%); }
  to   { transform: translateX(108%); }
}

09オーブボタン・チャット入力

AIに尋ねる丸い入力欄と、ソリッドのボタン2つです。フォーカスが当たると入力欄のまわりに4pxの光の輪が一重だけ付き、送信ボタンの中の8pxの点は押されると1.55倍にふくらみます。動きが小さく、画素が動いたのは23回の比較のうち12回と、9つの中でいちばん少なくなりました。

box-shadowtransitionaria-label
// 丸い入力欄。フォーカスの輪は box-shadow 一重だけ — 二重から先は球と光を取り合う
.ch__field {
  display: flex; align-items: center; gap: $sp-2;
  padding: $sp-2 $sp-2 $sp-2 $sp-4;
  border: 1px solid rgba($subject-cream, .18);
  border-radius: $r-pill;
  background: rgba($subject-cream, .08);
  box-shadow: 0 0 0 0 rgba($color, 0);
  transition: box-shadow $dur-base $easing, border-color $dur-base $easing;
}
.ch__field:focus-within {
  border-color: rgba($color, .62);
  box-shadow: 0 0 0 4px rgba($color, .34);
}
.ch__send:active .ch__dot { transform: scale(1.55); opacity: 1; }

tailwind.config カスタム

このキットで値を1か所に集める理由は、色より影の使い分けにあります。カードは静止でrest、ホバーでraisedに深まり、入力欄のフォーカスだけがhaloの光の輪を持ちます。この3つが混ざった瞬間に、画面のあちこちが光り始めて球が埋もれます。色の並びも同じ順で読めます。ink・surface・lineが台と面と線、cream・muteが文字、sky・brand・lilacが球の3段で、flameは07の台にだけ顔を出すアクセントです。

theme: {
  extend: {
    colors: {
      ink: "#17141a", surface: "#252228", line: "#332f38",
      cream: "#fff7e6", mute: "#beb7ad",
      sky: "#6ec8ff", brand: "#2f6df6", lilac: "#b9a0ff",
      flame: "#ff4d1f", paper: "#ffffff",
      pink: "#ff9ebb", mint: "#4cd4a6",
    },
    borderRadius: { card: "16px", control: "12px", chip: "4px", pill: "999px" },
    boxShadow: {
      rest: "0 6px 12px rgba(23,20,26,.32)",
      raised: "0 14px 24px rgba(23,20,26,.32)",
      halo: "0 0 0 4px rgba(185,160,255,.34)",
    },
    spacing: { gutter: "16px" },
  },
},
役割 トークン いつ使うか
bg-ink 9つのうち6つの背景。グラデーションは敷かない
カードの静止 shadow-rest 手を乗せていないカード
カードの浮き shadow-raised ホバー中とおすすめプランの1枚だけ
光の輪 shadow-halo 入力欄がフォーカスを受けたときだけ

角丸も同じ考えで4段しかありません。カードはrounded-cardの16px、ボタンと入力の枠はrounded-controlの12px、小さなチップは4px、丸い入力欄はrounded-pillです。球だけはこの4段から外して、必ずborder-radius: 50%にします。正円でないと重ねたハイライトの中心がずれて、球ではなく楕円のシールに見えてしまうからです。

バイブコーディング プロンプト

設定を置いたあとにClaude CodeやCursorへ渡す指示は、下のひとかたまりで足ります。色の一覧より先に「光らせてよい場所はどこか」を書く、この順番が効きます。切り詰める前の全文は、zipの中のprompt.mdに入れてあります。

背景は #17141a の単色で塗る。グラデーションもノイズも背景には敷かない。
光ってよいのは球だけ。球は写真でも filter: blur でもなく、radial-gradient を重ねて作る —
ハイライトを circle at 30% 30% に1枚、本体を1枚、その背後に光の輪を1枚。
球の色はページの上から順に sky #6ec8ff → brand #2f6df6 → lilac #b9a0ff の3段で降ろす。
ボタンはソリッドにする。光らせず、hover では translateY(-1px) と shadow-raised だけで応える。
球には aria-hidden="true" を付け、状態・順序・強調は文字と枠で必ず別に伝える。

この指示のうち、先に守られているか確かめるべきなのは最初の2行です。背景に1本でもグラデーションが入ると、残りの4行を完璧に書かせても球は目立ちません。返ってきたコードを直すときも、色の値に手を付ける前に「今この画面で光っている場所はいくつあるか」を数えるほうが近道です。5行目も消さずに残してください。ボタンを光らせてよいか迷ったときに最初に外れるのがこの行で、ボタンが光った瞬間に画面の主役が2つになります。

どこで壊れるか — 落とし穴

一番手こずったのは、ヒーローの見出しの改行でした。韓国語版は単語の途中で切れないようにword-break: keep-allを指定していますが、同じ指定を日本語の文に掛けると、日本語には単語の間の空白がないため改行できる場所そのものが消え、見出しが1行のまま横へ伸びます。そこで.ho__title:lang(ko):lang()で韓国語だけに限定し、日本語版と英語版は自動改行のまま残しました。同じ見出しを3言語で使い回すキットでは、台の幅よりも先に、文字の折り返し規則の差が画面を壊します。多言語のページで最初に壊れるのは、色でも動きでもなくこの改行です。

2つ目は、光の上に置いた文字の薄さでした。ほかの8つで問題なく読めていた「本文より一段薄い補助文」を07のCTA帯にそのまま持ち込むと、球が帯の中央へ漂ってきた瞬間だけ文字が沈みます。台が単色なら透明度は安全な階層の付け方ですが、背景そのものが明るくなる場所では成立しません。透明度をやめて、薄さの代わりに文字の大きさと太さで階層を作り直しました。

3つ目はanimationの書き方でした。03・04・06・08は行やカードを順にずらすためにanimation-delayを使いますが、一括指定のanimationを後から書くと、そこで挙げなかったanimation-delayが0sに戻ります。この4つはanimation-nameanimation-durationを個別プロパティで書き、遅延の待ち時間に素の状態が1コマ光らないようanimation-fill-mode: backwardsを添えました。ブラウザの仕様どおりの動きですが、一括指定のほうが短く書けるぶん、あとから触る人が無意識に書き戻してしまう場所でもあります。遅延が消えると04の6行は同時に光り、視線をリストの下へ運ぶという役目だけがそっくり消えます。9つの部品が入ったzipのパスワードは e3bm95my で、SCSSとコンパイル済みのCSS、React版がセクションごとに分かれて入っています。

アクセシビリティ

光は意味を運べません。球はすべてaria-hidden="true"で読み上げから外し、どの項目が今アクティブなのかは02のaria-current、送信ボタンの役割は09のaria-labelという、文字の側で伝えています。WCAG 2.1の最低コントラスト基準の相対輝度の式で、このキットの主な組み合わせを直接計算しました。

文字と地の組み合わせ 比率 判定
クリーム #fff7e6 / インク台 #17141a 17.11:1 合格
見出し上の空色 #6ec8ff / インク台 9.87:1 合格
補助文 クリーム72%(#beb7ad) / インク台 9.18:1 合格
CTA帯の見出し クリーム #fff7e6 / 球の上寄り #53528a 6.70:1 合格
CTA帯の補助文 クリーム #fff7e6 / 球の中心 #6e6096 5.22:1 合格
同じ補助文をクリーム72%にした場合 / 球の中心 3.58:1 不合格 — 光の上で薄くしてはいけない
料金プランの補助文 インク62% / 白い台 #ffffff 5.12:1 合格
ブランド色 #2f6df6 / インク台 4.03:1 装飾アイコン専用。本文には使わない

3.58:1の行が、このキットで最後まで残った不合格でした。ほかの台では9.18:1で余裕のあった同じクリーム72%の補助文が、球の中心を背にした瞬間だけAAを割ります。球の核を正面から受けるのは4つの要素のうち補助文だけで、ひとつ上の見出しが背にするのは球の上寄りの#53528aなので、そこでは6.70:1あります。11px・太さ500の文字は大きな文字の例外(3:1)も使えないので、補助文の透明度をやめてクリーム100%に上げ、5.22:1で通しました。球の中心のアルファを0.55で止めているのも同じ理由で、0.65まで上げると背景が#806fafになり、クリーム100%でも4.09:1まで落ちます。動きを減らす設定にしている訪問者には、9つともprefers-reduced-motionで動きだけを止め、見えている情報は残します。04は6行すべてを明るいまま止め、08は3つの球を20%・50%・62%の位置に置いたままにし、09は光の輪と入力中の文字を表示したまま固定します。球そのものはMDNのradial-gradientの値だけでできているので、対応していない環境でも単色の丸に落ちるだけでレイアウトは崩れません。

柔らかい影で同じ台を作るやり方はニューモーフィズムのLPキットに、質感で重みを出すやり方はスキューモーフィズムの質感パーツにあります。ほかの流行はデザインのカテゴリーにまとめてあります。

FAQ

背景にグラデーションを敷いてはいけませんか?

敷いた瞬間、球が背景に溶けます。このキットが球1つで「AIらしさ」を出せているのは、台が#17141aの1色で、光っている画素がほかにないからです。どうしても背景を動かしたいときは球のほうを消して、光るものをどちらか一方だけに絞ってください。

球はfilter: blurで作ってはだめですか?

ぼかしは面全体を再描画するので、9つ全部に掛けると非力な端末で目に見えて重くなります。ここでは球も光の輪もradial-gradientの重ねだけで作っていて、ぼかしは1か所も使っていません。グラデーション自体に硬い境界がないので、そもそもぼかす必要がありません。

球にスクリーンリーダー用の説明は要りませんか?

要りません。球は状態も順序も運んでいない装飾なので、aria-hidden="true"で読み上げから外すのが正解です。逆に「今ここが選ばれている」「この行が処理中」といった意味を球に持たせたいなら、その意味は文字か枠として別に書いてください。

解凍パスワードを入力してください

パスワードはこの記事の本文の中にあります。読み進めると出てきます。