04順に目覚める機能リスト
6行のミニオーブが上から順に明るくなり、また暗くなる2秒ループを回ります(animation-delay)。一度に一つだけ明るくなるので、視線が自然とリストを下っていきます。
使いどころ機能一覧・処理ステップの紹介
animation-delayopacityradial-gradient

<main class="stage">
<section class="fl is-demo" id="fl">
<p class="fl__eyebrow">
<span class="fl__ico" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M194.82,151.43l-55.09,20.3-20.3,55.09a7.92,7.92,0,0,1-14.86,0l-20.3-55.09-55.09-20.3a7.92,7.92,0,0,1,0-14.86l55.09-20.3,20.3-55.09a7.92,7.92,0,0,1,14.86,0l20.3,55.09,55.09,20.3A7.92,7.92,0,0,1,194.82,151.43Z" opacity="0.2"/><path d="M197.58,129.06,146,110l-19-51.62a15.92,15.92,0,0,0-29.88,0L78,110l-51.62,19a15.92,15.92,0,0,0,0,29.88L78,178l19,51.62a15.92,15.92,0,0,0,29.88,0L146,178l51.62-19a15.92,15.92,0,0,0,0-29.88ZM137,164.22a8,8,0,0,0-4.74,4.74L112,223.85,91.78,169A8,8,0,0,0,87,164.22L32.15,144,87,123.78A8,8,0,0,0,91.78,119L112,64.15,132.22,119a8,8,0,0,0,4.74,4.74L191.85,144ZM144,40a8,8,0,0,1,8-8h16V16a8,8,0,0,1,16,0V32h16a8,8,0,0,1,0,16H184V64a8,8,0,0,1-16,0V48H152A8,8,0,0,1,144,40ZM248,88a8,8,0,0,1-8,8h-8v8a8,8,0,0,1-16,0V96h-8a8,8,0,0,1,0-16h8V72a8,8,0,0,1,16,0v8h8A8,8,0,0,1,248,88Z"/></svg></span>
AIワークスペース
</p>
<h2 class="fl__title">順に目覚める6つの機能</h2>
<ul class="fl__list">
<li class="fl__row"><span class="fl__orb" aria-hidden="true"></span><span class="fl__label">ドキュメントから答えを探す</span></li>
<li class="fl__row"><span class="fl__orb" aria-hidden="true"></span><span class="fl__label">議事録を自動で要約</span></li>
<li class="fl__row"><span class="fl__orb" aria-hidden="true"></span><span class="fl__label">表データを整える</span></li>
<li class="fl__row"><span class="fl__orb" aria-hidden="true"></span><span class="fl__label">下書きを書き直す</span></li>
<li class="fl__row"><span class="fl__orb" aria-hidden="true"></span><span class="fl__label">トーンを合わせて翻訳</span></li>
<li class="fl__row"><span class="fl__orb" aria-hidden="true"></span><span class="fl__label">コードスニペットを作る</span></li>
</ul>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 변형은 이 셋만 바꾼다
$duration: $dur-loop; // 한 바퀴 2초. 여섯 행이 이 안에서 한 번씩 깬다 (2000 ÷ 6 = 334ms 간격)
$easing: $ease-out;
$color: $subject-blue;
@include stage($stage-ink);
// 오브 표면 — 왼쪽 위 하이라이트 한 겹 + 본체 한 겹. 가장자리는 무대 쪽으로 가라앉는다
@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%);
}
.fl { width: min(100%, 400px); }
.fl__eyebrow {
display: flex; align-items: center; gap: $sp-1; margin: 0;
font-weight: 700; font-size: clamp(8px, 2.4vw, 10px); line-height: 1; letter-spacing: .08em;
color: rgba(255, 255, 255, .72); // 잉크 무대 위 9.81:1 — 계산 2026-09-12
}
.fl__ico { display: inline-flex; width: 12px; height: 12px; flex: 0 0 auto; color: $color; } // 장식 아이콘, 잉크 위 4.03:1
.fl__ico svg { width: 100%; height: 100%; }
.fl__title {
margin: $sp-1 0 0; font-weight: 800; font-size: clamp(13px, 3.6vw, 16px); line-height: 1.25;
color: $subject-cream; // 잉크 위 16.2:1
}
.fl__list { list-style: none; margin: $sp-3 0 0; padding: 0; }
.fl__row {
display: grid; grid-template-columns: 14px 1fr; align-items: center; gap: $sp-3;
padding: $sp-1 0; border-top: 1px solid rgba(255, 255, 255, .1);
}
.fl__row:first-child { border-top: 0; }
// 빛 무리는 box-shadow 한 겹. opacity 가 요소째 흐려지므로 오브가 어두워질 때 무리도 같이 죽는다
.fl__orb { width: 14px; height: 14px; border-radius: 50%; box-shadow: 0 0 10px rgba($color, .5); @include orbSkin($color); }
.fl__label {
font-weight: 600; font-size: clamp(10px, 3vw, 12px); line-height: 1.3;
color: $subject-cream; // 루프의 가장 어두운 순간(opacity .62)에도 잉크 위 7.09:1
}
// ── 미리보기 루프: 오브가 위에서 아래로 한 칸씩 깬다
// animation 단축을 쓰면 delay 가 0s 로 리셋된다 → 낱개 속성으로. 지연이 걸리므로 fill-mode: backwards 필수
.fl.is-demo .fl__orb,
.fl.is-demo .fl__label {
animation-duration: $duration; animation-timing-function: $easing;
animation-iteration-count: infinite; animation-fill-mode: backwards;
}
.fl.is-demo .fl__orb { animation-name: flWake; }
.fl.is-demo .fl__label { animation-name: flLabelWake; }
.fl.is-demo .fl__row:nth-child(1) .fl__orb, .fl.is-demo .fl__row:nth-child(1) .fl__label { animation-delay: 0ms; }
.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; }
.fl.is-demo .fl__row:nth-child(4) .fl__orb, .fl.is-demo .fl__row:nth-child(4) .fl__label { animation-delay: 1000ms; }
.fl.is-demo .fl__row:nth-child(5) .fl__orb, .fl.is-demo .fl__row:nth-child(5) .fl__label { animation-delay: 1334ms; }
.fl.is-demo .fl__row:nth-child(6) .fl__orb, .fl.is-demo .fl__row:nth-child(6) .fl__label { animation-delay: 1667ms; }
// 밝은 구간은 16%(320ms) 로 끝난다 — 다음 행이 깨는 334ms 보다 짧아야 한 번에 하나만 밝다
@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); }
}
@keyframes flLabelWake {
0% { opacity: .62; }
5% { opacity: 1; }
11% { opacity: 1; }
16% { opacity: .62; }
100% { opacity: .62; }
}
// ── 320×200 폰 압축 (BD9). 이 안에서는 간격을 올리지 않는다
@media (max-width: 340px), (max-height: 220px) {
.fl__eyebrow { font-size: 8px; }
.fl__ico { width: 10px; height: 10px; }
.fl__title { font-size: 11px; }
.fl__list { margin-top: $sp-2; }
.fl__row { grid-template-columns: 10px 1fr; gap: $sp-2; }
.fl__orb { width: 10px; height: 10px; }
.fl__label { font-size: 9px; }
}
@media (prefers-reduced-motion: reduce) {
.fl.is-demo .fl__orb,
.fl.is-demo .fl__label { animation: none !important; opacity: 1 !important; transform: none !important; }
}html, body {
margin: 0;
overflow: hidden;
}
.stage {
box-sizing: border-box;
min-height: 100vh;
display: grid;
place-items: center;
margin: 0;
background: #17141a;
font-family: -apple-system, "Segoe UI", "Noto Sans KR", sans-serif;
padding: clamp(8px, 4vw, 24px);
}
.fl {
width: min(100%, 400px);
}
.fl__eyebrow {
display: flex;
align-items: center;
gap: 4px;
margin: 0;
font-weight: 700;
font-size: clamp(8px, 2.4vw, 10px);
line-height: 1;
letter-spacing: 0.08em;
color: rgba(255, 255, 255, 0.72);
}
.fl__ico {
display: inline-flex;
width: 12px;
height: 12px;
flex: 0 0 auto;
color: #2f6df6;
}
.fl__ico svg {
width: 100%;
height: 100%;
}
.fl__title {
margin: 4px 0 0;
font-weight: 800;
font-size: clamp(13px, 3.6vw, 16px);
line-height: 1.25;
color: #fff7e6;
}
.fl__list {
list-style: none;
margin: 12px 0 0;
padding: 0;
}
.fl__row {
display: grid;
grid-template-columns: 14px 1fr;
align-items: center;
gap: 12px;
padding: 4px 0;
border-top: 1px solid rgba(255, 255, 255, 0.1);
}
.fl__row:first-child {
border-top: 0;
}
.fl__orb {
width: 14px;
height: 14px;
border-radius: 50%;
box-shadow: 0 0 10px rgba(47, 109, 246, 0.5);
background: radial-gradient(circle at 34% 26%, rgba(255, 255, 255, 0.92) 0%, rgba(255, 255, 255, 0) 44%), radial-gradient(circle at 52% 54%, #2f6df6 0%, rgba(47, 109, 246, 0.45) 58%, rgba(23, 20, 26, 0.92) 100%);
}
.fl__label {
font-weight: 600;
font-size: clamp(10px, 3vw, 12px);
line-height: 1.3;
color: #fff7e6;
}
.fl.is-demo .fl__orb,
.fl.is-demo .fl__label {
animation-duration: 2s;
animation-timing-function: ease-out;
animation-iteration-count: infinite;
animation-fill-mode: backwards;
}
.fl.is-demo .fl__orb {
animation-name: flWake;
}
.fl.is-demo .fl__label {
animation-name: flLabelWake;
}
.fl.is-demo .fl__row:nth-child(1) .fl__orb, .fl.is-demo .fl__row:nth-child(1) .fl__label {
animation-delay: 0ms;
}
.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;
}
.fl.is-demo .fl__row:nth-child(4) .fl__orb, .fl.is-demo .fl__row:nth-child(4) .fl__label {
animation-delay: 1000ms;
}
.fl.is-demo .fl__row:nth-child(5) .fl__orb, .fl.is-demo .fl__row:nth-child(5) .fl__label {
animation-delay: 1334ms;
}
.fl.is-demo .fl__row:nth-child(6) .fl__orb, .fl.is-demo .fl__row:nth-child(6) .fl__label {
animation-delay: 1667ms;
}
@keyframes flWake {
0% {
opacity: 0.32;
transform: scale(0.86);
}
5% {
opacity: 1;
transform: scale(1.18);
}
11% {
opacity: 1;
transform: scale(1.06);
}
16% {
opacity: 0.32;
transform: scale(0.86);
}
100% {
opacity: 0.32;
transform: scale(0.86);
}
}
@keyframes flLabelWake {
0% {
opacity: 0.62;
}
5% {
opacity: 1;
}
11% {
opacity: 1;
}
16% {
opacity: 0.62;
}
100% {
opacity: 0.62;
}
}
@media (max-width: 340px), (max-height: 220px) {
.fl__eyebrow {
font-size: 8px;
}
.fl__ico {
width: 10px;
height: 10px;
}
.fl__title {
font-size: 11px;
}
.fl__list {
margin-top: 8px;
}
.fl__row {
grid-template-columns: 10px 1fr;
gap: 8px;
}
.fl__orb {
width: 10px;
height: 10px;
}
.fl__label {
font-size: 9px;
}
}
@media (prefers-reduced-motion: reduce) {
.fl.is-demo .fl__orb,
.fl.is-demo .fl__label {
animation: none !important;
opacity: 1 !important;
transform: none !important;
}
}import styles from "./FeatureListOrb.module.scss";
export type FeatureListOrbProps = {
/** 한 바퀴(ms). 행 수로 나눈 값이 행 사이 간격이 된다 */
duration?: number;
easing?: string;
/** 오브 색. 6자리 hex 로 준다 (#2f6df6) */
color?: string;
};
const FEATURES = [
"문서에서 답 찾기",
"회의록 자동 요약",
"표 데이터 정리",
"초안 다시 쓰기",
"말투 맞춰 번역",
"코드 조각 만들기",
];
// 6자리 hex 에 알파 두 자리를 붙인다 — #2f6df6 + "73" 꼴
function withAlpha(hex: string, alpha: number): string {
const n = Math.round(alpha * 255);
return hex + (n < 16 ? "0" : "") + n.toString(16);
}
export default function FeatureListOrb({
duration = 2000,
easing = "ease-out",
color = "#2f6df6",
}: FeatureListOrbProps) {
const orbSkin = {
background:
"radial-gradient(circle at 34% 26%, rgba(255, 255, 255, 0.92) 0%, rgba(255, 255, 255, 0) 44%), " +
"radial-gradient(circle at 52% 54%, " + color + " 0%, " + withAlpha(color, 0.45) + " 58%, rgba(23, 20, 26, 0.92) 100%)",
boxShadow: "0 0 10px " + withAlpha(color, 0.5),
};
// animation 단축을 쓰면 delay 가 0s 로 리셋된다 → 낱개로. 지연이 걸리므로 fill-mode 는 scss 쪽에서 backwards
const loop = (i: number) => ({
animationDuration: duration + "ms",
animationTimingFunction: easing,
animationDelay: Math.round((duration / FEATURES.length) * i) + "ms",
});
return (
<main className={styles.stage}>
<section className={`${styles.fl} ${styles.demoLoop}`}>
<p className={styles.eyebrow}>
<span className={styles.ico} aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M194.82,151.43l-55.09,20.3-20.3,55.09a7.92,7.92,0,0,1-14.86,0l-20.3-55.09-55.09-20.3a7.92,7.92,0,0,1,0-14.86l55.09-20.3,20.3-55.09a7.92,7.92,0,0,1,14.86,0l20.3,55.09,55.09,20.3A7.92,7.92,0,0,1,194.82,151.43Z" opacity="0.2"/><path d="M197.58,129.06,146,110l-19-51.62a15.92,15.92,0,0,0-29.88,0L78,110l-51.62,19a15.92,15.92,0,0,0,0,29.88L78,178l19,51.62a15.92,15.92,0,0,0,29.88,0L146,178l51.62-19a15.92,15.92,0,0,0,0-29.88ZM137,164.22a8,8,0,0,0-4.74,4.74L112,223.85,91.78,169A8,8,0,0,0,87,164.22L32.15,144,87,123.78A8,8,0,0,0,91.78,119L112,64.15,132.22,119a8,8,0,0,0,4.74,4.74L191.85,144ZM144,40a8,8,0,0,1,8-8h16V16a8,8,0,0,1,16,0V32h16a8,8,0,0,1,0,16H184V64a8,8,0,0,1-16,0V48H152A8,8,0,0,1,144,40ZM248,88a8,8,0,0,1-8,8h-8v8a8,8,0,0,1-16,0V96h-8a8,8,0,0,1,0-16h8V72a8,8,0,0,1,16,0v8h8A8,8,0,0,1,248,88Z"/></svg>
</span>
AI 워크스페이스
</p>
<h2 className={styles.title}>차례로 깨어나는 기능 6가지</h2>
<ul className={styles.list}>
{FEATURES.map((feature, i) => (
<li className={styles.row} key={feature}>
<span className={styles.orb} aria-hidden="true" style={{ ...orbSkin, ...loop(i) }} />
<span className={styles.label} style={loop(i)}>{feature}</span>
</li>
))}
</ul>
</section>
</main>
);
}04 順に目覚める機能リスト — 計測 累積面積 4.368% · 動いたフレーム 23/23GODRICH オリジナル · SCSS と React は zip に同梱 · ai ランディングページ 光るオーブ デザインキット、セクション9選
このデモが属する記事
ai ランディングページ 光るオーブ デザインキット、セクション9選ai ランディングページの光るオーブとは、台になる背景を単色のまま置いて、画面の中で光るものを丸い球ひとつに絞る作り方です。グラデーション背景なしでもAIらしく見えるこの手を、ヒーローからフッターまで貼って使える9つのセクションにまとめまし この記事のデモをすべて見る


