우주정거장 인물소개 화면에 쓴 디자인 요소를 뜯어 정리했다. 팔레트·효과·애니메이션 전부 의존성 0의 순수 CSS이며, 각 블록은 그대로 복사해 쓸 수 있다.
← 카탈로그로우주정거장 내부는 따뜻한 실내 조명(amber)과 차가운 데이터·창밖(cyan) 두 광원이 대비를 만든다. 이 둘만 강조색으로 쓰고 나머지는 전부 무채색으로 눌러야 화면이 정리된다. 강조색을 셋 이상 쓰면 HUD 가 아니라 크리스마스 트리가 된다.
:root{ --ink:#05070c; /* 배경 최심부 */ --panel:#0d1219; /* 패널 */ --line:#26303f; /* 경계선 */ --dim:#8b97a8; /* 보조 텍스트 */ --txt:#e8edf5; /* 본문 */ --amber:#ffb547; /* 강조 1 — 따뜻한 실내광 */ --cyan:#5fd4ff; /* 강조 2 — 차가운 데이터광 */ --violet:#a78bfa; /* 홀로그램 보조 */ }
인물 초상을 담는 원형 프레임. 핵심은 conic-gradient 를 mask 로 도넛만 남기는 것이다.
안쪽을 마스크로 뚫어야 내용물을 가리지 않고 테두리만 빛난다. filter:blur 로 번지게 하면 발광처럼 보인다.
/* 도넛 글로우 — 안쪽을 mask 로 뚫는 게 핵심 */ .ring::before{ content:""; position:absolute; inset:-9px; border-radius:50%; background:conic-gradient(from 0deg,transparent 0deg, var(--cyan) 40deg,#fff 70deg,var(--amber) 110deg,transparent 170deg); filter:blur(6px); animation:ringSpin 9s linear infinite; mask:radial-gradient(circle,transparent 0 49.2%,#000 49.6%); } @keyframes ringSpin{ to{ rotate:360deg } } /* 눈금 틱 — transform-origin 을 반지름만큼 내려 방사 배치 */ .ticks i{ position:absolute; left:50%; top:0; width:2px; height:9px; background:rgba(255,255,255,.34); transform-origin:50% 77px; /* = 원 반지름 */ } // JS: 36개를 10도 간격으로 for(let i=0;i<36;i++){ t.style.rotate = i*10+'deg'; } /* 홀로 시머 — 넓은 그라디언트를 가로로 흘린다 */ .holo::after{ background:linear-gradient(115deg,transparent 34%, rgba(167,139,250,.28) 47%,rgba(95,212,255,.3) 53%,transparent 66%); background-size:280% 100%; animation:holo 3.4s linear infinite; } @keyframes holo{ to{ background-position:-280% 0 } }
배경이 그냥 이미지로 보이지 않게 만드는 세 겹. 비네트가 시선을 중앙으로 모으고,
스캔라인이 화면에 질감을 주고, 라이트 스윕이 정지된 화면에 생기를 넣는다.
전부 pointer-events:none 인 오버레이라 클릭을 방해하지 않는다.
/* 비네트 — 가장자리를 눌러 시선을 중앙으로 */ .vignette{ position:absolute; inset:0; pointer-events:none; background:radial-gradient(ellipse at 50% 45%, transparent 30%,rgba(0,0,0,.55) 72%,rgba(0,0,0,.88) 100%); } /* 스캔라인 — 1px 선을 3px 간격으로. overlay 로 은은하게 */ .grain{ opacity:.05; mix-blend-mode:overlay; background-image:repeating-linear-gradient(0deg,#fff 0 1px,transparent 1px 3px); } /* 라이트 스윕 — 화면을 가로지르는 빛 */ @keyframes sweep{ 0%{left:-40%} 55%,100%{left:120%} } /* 배경 드리프트 — 아주 느린 확대. 정지컷을 살아있게 */ @keyframes bgDrift{ from{transform:scale(1.06)} to{transform:scale(1.13)} } .bg.on{ animation:bgDrift 14s ease-out forwards } /* 코너 브래킷 — 네 모서리에 ㄱ 자 */ .hudbox b{ position:absolute; width:16px; height:16px; border:2px solid var(--cyan) } .hudbox b:nth-child(1){ top:-1px; left:-1px; border-right:0; border-bottom:0 }
이름이 한 글자씩 blur 가 풀리며 올라온다. 글자당 0.085초씩 밀면 3글자 이름이 약 0.25초에 완성돼 읽는 리듬과 맞는다. 아래 데모를 클릭하면 다시 재생된다.
.26em)을 한글에 그대로 쓰면
"전 동 화 소 음 진 동"처럼 글자가 흩어져 읽기 어려워진다.
글자 수에 따라 11자↑ .09em / 8자↑ .14em / 그 외 .2em 으로 줄이는 게 안전하다.
/* 글자별 등장 — blur 가 풀리며 올라온다 */ .name span{ display:inline-block; opacity:0; translate:0 34px; filter:blur(9px); animation:charIn .62s cubic-bezier(.2,.9,.25,1) forwards; } @keyframes charIn{ to{ opacity:1; translate:0 0; filter:blur(0) } } // JS: 글자당 0.085초씩 지연 [...name].forEach((ch,k)=>{ s.textContent = ch; s.style.animationDelay = (0.55 + k*0.085) + 's'; }); /* 좌우로 그려지는 구분선 */ .bar{ width:0; height:2px; background:linear-gradient(90deg,transparent,var(--amber),transparent) } @keyframes barGrow{ to{ width:330px } } /* 한글 자간 — 길이에 따라 자동 조절 */ ko.style.setProperty('--ts', body.length >= 11 ? '.09em' : body.length >= 8 ? '.14em' : '.2em');
720×1280 세로 영상을 원형 프레임에 넣으면 object-fit:cover 가 위아래를 잘라낸다.
어디를 남길지는 object-position, 얼마나 당길지는 transform:scale 이 정한다.
사람마다 손으로 맞추면 절대 균일해지지 않으므로 얼굴 검출로 역산했다.
.disc{ width:100%; aspect-ratio:1; border-radius:50%; overflow:hidden; clip-path:circle(50%) } .disc video{ width:100%; height:100%; object-fit:cover } /* 인물마다 다른 두 값 — 자동 계산한다 */ video.style.objectPosition = `50% ${focus}%`; video.style.scale = scale; /* 원 안쪽 하단을 눌러 이름과 자연스럽게 연결 */ .disc .fade{ position:absolute; inset:0; pointer-events:none; background:linear-gradient(to bottom,transparent 58%,rgba(5,7,12,.75) 100%) }
R 은 영상 세로/가로 비.
cover 로 영상은 원 지름 D 폭에 맞춰지고 세로가 D·R 이 되어 넘친다.t0 = -D·(R-1)·p/100 · y_screen = D/2 + (t0 + y·D·R - D/2)·sp(focus)와 s(scale)에 대해 풀면 모든 인원의
얼굴이 같은 자리·같은 크기에 놓인다. p 가 음수로 나와도 정상이다 —
object-position 은 음수 % 를 받는다.
1. 강조색은 둘까지. amber(따뜻한 실내광) + cyan(차가운 데이터광). 셋째를 넣는 순간 HUD 가 아니게 된다.
2. 움직임은 느리게. 링 9초, 배경 14초, 홀로 3.4초. 빠른 모션은 싸구려로 보인다.
3. 정보는 모서리로. 중앙은 인물, 코드·상태는 네 모서리. HUD 문법이다.
4. 영문은 각지게, 한글은 굵게. Orbitron(라벨·코드) + Gothic A1 900(이름).
5. 오버레이는 클릭을 막지 않는다. 비네트·스캔라인 전부 pointer-events:none.
6. 모션 축소 설정을 존중한다. @media (prefers-reduced-motion:reduce) 로 전부 끈다.
@media (prefers-reduced-motion:reduce){ *{ animation:none !important; transition:none !important } }