01떠오르는 오브 히어로
짙은 잉크 배경 위에 겹으로 쌓은 radial-gradient 오브가 천천히 떠올랐다 내려앉기를 반복하고(translateY), 그 주위의 흐린 빛 무리가 같은 2초 주기로 맥박칩니다. 오브는 장식이므로 스크린 낭독기에서는 숨깁니다.
쓰임AI 제품 랜딩 첫 화면
radial-gradienttranslateYscalearia-hidden

<main class="stage">
<section class="ho">
<div class="ho__text">
<p class="ho__eyebrow">
<span class="ho__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>
새 모델 공개
</p>
<h1 class="ho__title">묻기만 하면 초안이 나옵니다</h1>
<p class="ho__sub">회의록·기획서·메일을 한 번에 정리합니다.</p>
<a class="ho__cta" href="#" role="button">무료로 시작하기<span class="ho__arrow" aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M216,128l-72,72V56Z" opacity="0.2"/><path d="M221.66,122.34l-72-72A8,8,0,0,0,136,56v64H40a8,8,0,0,0,0,16h96v64a8,8,0,0,0,13.66,5.66l72-72A8,8,0,0,0,221.66,122.34ZM152,180.69V75.31L204.69,128Z"/></svg></span></a>
</div>
<div class="ho__orbwrap" aria-hidden="true">
<span class="ho__halo"></span>
<span class="ho__orb"></span>
</div>
</section>
</main>@use "../../../../site/static/demo-tokens" as *;
// 변수 3개 — 변형은 이 셋만 바꾼다
$duration: $dur-loop; // 떠오름·맥박 한 주기 (설정 `초` 와 같은 2s)
$easing: ease-in-out; // 위아래 왕복은 양끝에서 멎어야 숨쉬듯 보인다
$color: $subject-sky; // 오브의 빛 색
// 이 편 아홉 항목은 전부 잉크 무대다 — 빛나는 오브는 어두운 바탕에서만 빛으로 읽힌다
@include stage($stage-ink);
.ho {
display: grid; grid-template-columns: 1fr auto; align-items: center; gap: $sp-5;
width: min(100%, 432px);
}
// 대비 실측(WCAG 상대휘도로 계산): 무대 $stage-ink 의 상대휘도 0.00757
.ho__eyebrow {
display: flex; align-items: center; gap: $sp-1; margin: 0 0 $sp-2;
font-weight: 700; font-size: 10px; line-height: 1; letter-spacing: .04em;
color: $color; // $subject-sky on $stage-ink = 9.87:1
}
.ho__ico { display: inline-flex; width: 12px; height: 12px; flex: 0 0 auto; }
.ho__ico svg { width: 100%; height: 100%; }
.ho__title {
margin: 0; font-weight: 800; font-size: clamp(17px, 5.2vw, 25px); line-height: 1.18;
letter-spacing: -.01em; color: $subject-cream; // $subject-cream on $stage-ink = 17.11:1
}
// keep-all 은 한국어에만 — 어절 가운데서 끊기지 않게 한다(묻기만 하면 / 초안이 나옵니다).
// 일본어에 걸면 띄어쓰기가 없어 줄바꿈 자리가 사라지고 가로로 넘친다 (ja 사본 480×300 실측 2026-09-12)
.ho__title:lang(ko) {
word-break: keep-all;
}
.ho__sub {
margin: $sp-2 0 0; font-weight: 500; font-size: clamp(10px, 2.8vw, 12px); line-height: 1.45;
color: rgba(255, 247, 230, .72); // 잉크 위에서 #beb7ad 로 합성 = 9.18:1
}
.ho__cta {
display: inline-flex; align-items: center; gap: $sp-1; margin-top: $sp-4;
padding: $sp-2 $sp-4; border-radius: $r-pill;
background: $subject-cream; color: $subject-ink; // 크림 위 잉크 글자 = 17.11:1
font-weight: 700; font-size: 11px; line-height: 1; text-decoration: none;
}
.ho__arrow { display: inline-flex; width: 12px; height: 12px; }
.ho__arrow svg { width: 100%; height: 100%; }
// ── 오브: 겹으로 쌓은 radial-gradient 네 겹 = 하이라이트 · 빛 · 반사 · 코어
.ho__orbwrap {
position: relative; width: 152px; height: 152px; flex: 0 0 auto;
display: grid; place-items: center;
}
.ho__orb {
position: relative; z-index: 1; width: 104px; height: 104px; border-radius: 50%;
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;
}
// 빛 무리 — 오브와 같은 2초 주기로 커졌다 작아진다. 자기 중심에서 커진다 (blog-demo 규칙 8)
.ho__halo {
position: absolute; inset: 0; border-radius: 50%; transform-origin: 50% 50%;
background: radial-gradient(circle at 50% 50%, rgba(110, 200, 255, .42), rgba(110, 200, 255, .16) 48%, rgba(110, 200, 255, 0) 72%);
animation-name: hoPulse; animation-duration: $duration; animation-timing-function: $easing;
animation-iteration-count: infinite;
}
// translateY 왕복 — 0%·100% 가 같은 값이라 루프 이음매가 없다
@keyframes hoFloat {
0%, 100% { transform: translateY(7px); }
50% { transform: translateY(-7px); }
}
// scale 최대가 1 — 커져도 감싼 상자(152px) 밖으로 안 나간다. 넘침(BD9) 방지
@keyframes hoPulse {
0%, 100% { transform: scale(.82); opacity: .5; }
50% { transform: scale(1); opacity: .9; }
}
// ── 320×200 폰 실측 대비 압축 (BD9)
@media (max-width: 340px), (max-height: 220px) {
.ho { gap: $sp-3; }
.ho__eyebrow { margin-bottom: $sp-1; font-size: 9px; }
.ho__title { font-size: 15px; }
.ho__sub { margin-top: $sp-1; font-size: 9px; }
.ho__cta { margin-top: $sp-2; padding: $sp-1 $sp-3; font-size: 10px; }
.ho__orbwrap { width: 96px; height: 96px; }
.ho__orb { width: 68px; height: 68px; }
}
@media (prefers-reduced-motion: reduce) {
.ho__orb, .ho__halo { animation: none !important; transform: none !important; opacity: .9 !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);
}
.ho {
display: grid;
grid-template-columns: 1fr auto;
align-items: center;
gap: 20px;
width: min(100%, 432px);
}
.ho__eyebrow {
display: flex;
align-items: center;
gap: 4px;
margin: 0 0 8px;
font-weight: 700;
font-size: 10px;
line-height: 1;
letter-spacing: 0.04em;
color: #6ec8ff;
}
.ho__ico {
display: inline-flex;
width: 12px;
height: 12px;
flex: 0 0 auto;
}
.ho__ico svg {
width: 100%;
height: 100%;
}
.ho__title {
margin: 0;
font-weight: 800;
font-size: clamp(17px, 5.2vw, 25px);
line-height: 1.18;
letter-spacing: -0.01em;
color: #fff7e6;
}
.ho__title:lang(ko) {
word-break: keep-all;
}
.ho__sub {
margin: 8px 0 0;
font-weight: 500;
font-size: clamp(10px, 2.8vw, 12px);
line-height: 1.45;
color: rgba(255, 247, 230, 0.72);
}
.ho__cta {
display: inline-flex;
align-items: center;
gap: 4px;
margin-top: 16px;
padding: 8px 16px;
border-radius: 999px;
background: #fff7e6;
color: #17141a;
font-weight: 700;
font-size: 11px;
line-height: 1;
text-decoration: none;
}
.ho__arrow {
display: inline-flex;
width: 12px;
height: 12px;
}
.ho__arrow svg {
width: 100%;
height: 100%;
}
.ho__orbwrap {
position: relative;
width: 152px;
height: 152px;
flex: 0 0 auto;
display: grid;
place-items: center;
}
.ho__orb {
position: relative;
z-index: 1;
width: 104px;
height: 104px;
border-radius: 50%;
background: radial-gradient(circle at 34% 28%, rgba(255, 255, 255, 0.92), rgba(255, 255, 255, 0) 44%), radial-gradient(circle at 28% 66%, rgba(110, 200, 255, 0.9), rgba(110, 200, 255, 0) 58%), radial-gradient(circle at 74% 72%, rgba(185, 160, 255, 0.8), rgba(185, 160, 255, 0) 56%), radial-gradient(circle at 50% 50%, rgba(47, 109, 246, 0.95) 10%, rgba(23, 20, 26, 0.96) 92%);
animation-name: hoFloat;
animation-duration: 2s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
.ho__halo {
position: absolute;
inset: 0;
border-radius: 50%;
transform-origin: 50% 50%;
background: radial-gradient(circle at 50% 50%, rgba(110, 200, 255, 0.42), rgba(110, 200, 255, 0.16) 48%, rgba(110, 200, 255, 0) 72%);
animation-name: hoPulse;
animation-duration: 2s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
@keyframes hoFloat {
0%, 100% {
transform: translateY(7px);
}
50% {
transform: translateY(-7px);
}
}
@keyframes hoPulse {
0%, 100% {
transform: scale(0.82);
opacity: 0.5;
}
50% {
transform: scale(1);
opacity: 0.9;
}
}
@media (max-width: 340px), (max-height: 220px) {
.ho {
gap: 12px;
}
.ho__eyebrow {
margin-bottom: 4px;
font-size: 9px;
}
.ho__title {
font-size: 15px;
}
.ho__sub {
margin-top: 4px;
font-size: 9px;
}
.ho__cta {
margin-top: 8px;
padding: 4px 12px;
font-size: 10px;
}
.ho__orbwrap {
width: 96px;
height: 96px;
}
.ho__orb {
width: 68px;
height: 68px;
}
}
@media (prefers-reduced-motion: reduce) {
.ho__orb, .ho__halo {
animation: none !important;
transform: none !important;
opacity: 0.9 !important;
}
}import styles from "./HeroOrb.module.scss";
export type HeroOrbProps = { duration?: string; easing?: string; color?: string };
export default function HeroOrb({ duration = "2s", easing = "ease-in-out", color = "#6ec8ff" }: HeroOrbProps) {
// 변수 3개는 props 로 — 오브가 한 번 떠올랐다 내려앉는 시간 · 그 이징 · 빛 색
const motion = { animationDuration: duration, animationTimingFunction: easing };
return (
<main className={styles.stage}>
<section className={styles.ho}>
<div className={styles.text}>
<p className={styles.eyebrow} style={{ color }}>
<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>
새 모델 공개
</p>
<h1 className={styles.title}>묻기만 하면 초안이 나옵니다</h1>
<p className={styles.sub}>회의록·기획서·메일을 한 번에 정리합니다.</p>
<a className={styles.cta} href="#" role="button" onClick={(e: { preventDefault: () => void }) => { e.preventDefault(); }}>
무료로 시작하기
<span className={styles.arrow} aria-hidden="true">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor"><path d="M216,128l-72,72V56Z" opacity="0.2"/><path d="M221.66,122.34l-72-72A8,8,0,0,0,136,56v64H40a8,8,0,0,0,0,16h96v64a8,8,0,0,0,13.66,5.66l72-72A8,8,0,0,0,221.66,122.34ZM152,180.69V75.31L204.69,128Z"/></svg>
</span>
</a>
</div>
<div className={styles.orbwrap} aria-hidden="true">
<span className={styles.halo} style={motion} />
<span className={styles.orb} style={motion} />
</div>
</section>
</main>
);
}01 떠오르는 오브 히어로 — 측정 누적면적 9.735% · 움직인 프레임 23/23GODRICH 원작 · zip 에 SCSS·React 포함 · ai 랜딩페이지 오브 디자인 키트, 빛나는 섹션 9개
이 데모가 속한 글
ai 랜딩페이지 오브 디자인 키트, 빛나는 섹션 9개ai 랜딩페이지 오브 디자인은 화면 전체를 물들이는 대신 짙은 단색 무대 위에 빛나는 구슬 하나만 올려 제품의 성격을 말하는 방식입니다. 배경 그라디언트 없이도 AI 다워 보인다는 이 계산을 섹션 아홉 개로 잘라 정 이 글의 데모 전부 보기


