9개의 글자로 만든 DUOLABS AI STUDIO 브랜드 인트로 제작기
브랜드 인트로를 만들면서 출발점은 로고 모양이 아니라 문자 수였습니다. DUOLABS AI STUDIO를 적어 놓고 중복을 걷어내니 남는 글자는 D, U, O, L, A, B, S, I, T 아홉 개였습니다. 3×3 격자 하나를 채우기에 정확한 숫자였습니다.
처음에는 이 아홉 글자를 모두 슬롯머신처럼 돌렸습니다. 화면은 화려했지만 DUOLABS까지 늦게 읽혔고, 무엇을 보여주려는지 한 번에 들어오지 않았습니다. IT가 왼쪽에서 밀려 들어오는 안도 만들어 봤습니다. 그것도 설명적이었습니다. 결국 DUOLABS 일곱 글자는 처음부터 고정하고 I와 T의 두 자리만 비워 두기로 했습니다.
아홉 칸을 원소표처럼 사용하기
격자는 D·U·O / L·A·B / S·I·T 순서입니다. 각 칸의 글자는 단순한 장식이 아니라 최종 워드마크를 찍어내는 원형입니다. 처음 화면에는 DUOLABS만 있고 I와 T는 없습니다.
원형에서 글자가 복제되면 아래에 DUOLABS가 먼저 만들어집니다. 여기서 바로 다음 문장으로 넘어가니 두 줄이 한꺼번에 쏟아지는 것처럼 보였습니다. DUOLABS가 완성된 뒤 짧게 멈추고, 그 다음에 ASUDO가 별도 구문처럼 나타나도록 시간을 분리했습니다.
ASUDO는 AI STUDIO에서 I·T·I가 빠진 상태입니다.
- A는 AI에서 I가 빠졌습니다.
- SUDO는 STUDIO에서 T와 I가 빠졌습니다.
우연히 개발자에게 익숙한 sudo가 만들어졌습니다. 한때 A와 SUDO 사이를 벌리고 커서까지 붙여 이 의미를 강조했습니다. 화면을 다시 보니 농담을 설명하느라 인트로가 바빠졌습니다. 커서를 지우고, 자간을 벌리는 동작도 지웠습니다. ASUDO가 조용히 고정되어 있는 쪽이 나았습니다.
잠시 뒤 빈 두 칸에서만 슬롯이 돌아갑니다. I와 T가 멈추면 아래 문장의 빈 자리도 I → T → I 순서로 채워져 AISTUDIO가 됩니다. 마지막에 AI와 STUDIO 사이의 간격이 열리고, 격자가 사라지면서 완성된 두 줄이 화면 중앙으로 올라옵니다.
사용 횟수 자체를 애니메이션으로 만들기
격자가 마방진처럼 보여서 각 칸 오른쪽 아래에 작은 숫자를 붙였습니다. 화학 원소 카드의 원자번호처럼 보이지만 실제 값은 그 글자가 워드마크에 사용된 횟수입니다. 모두 0에서 시작하고 글자가 복제될 때마다 1씩 증가합니다.
최종 횟수는 다음과 같습니다.
D U O L A B S I T
2 2 2 1 2 1 2 2 1격자 아래에는 아홉 자리를 붙인 집계판도 놓았습니다.
000000000
111111100
222121200
222121221처음 구현은 CSS 레이어를 미리 쌓고 단계별로 보여주는 방식이었습니다. 첫 증가는 보였지만 같은 글자가 두 번째로 사용될 때 릴이 다시 시작되지 않는 경우가 있었습니다. 집계판만 React 상태로 분리하고, 값이 바뀔 때마다 revision 키를 올려 릴을 새로 마운트했습니다. 이제 0→1뿐 아니라 1→2에서도 임의 숫자 두 개를 빠르게 통과한 뒤 목표값에 멈춥니다.
setMatrixCode((current) =>
current.map((entry, index) =>
index === cellIndex
? {
value: entry.value + 1,
revision: entry.revision + 1,
}
: entry,
),
);숫자를 무작위로 만들지는 않았습니다. 셀 위치와 revision으로 중간 숫자를 계산해 같은 렌더링에서 결과가 달라지지 않게 했습니다. 실제 값이 바뀌는 시점은 글자 출력과 같은 스케줄을 공유합니다. 눈으로 비슷하게 맞춘 두 애니메이션이 아니라 하나의 타임라인을 숫자와 글자가 같이 읽습니다.
폰트를 기다리지 않는 글자 이동
인트로 글자는 일반 텍스트가 아니라 SVG 패스로 그렸습니다. 첫 프레임에서 폰트가 아직 준비되지 않았을 때 글자 폭이 바뀌면, 격자에서 워드마크로 이동하는 좌표가 흔들리기 때문입니다.
최종 위치와 원형 위치는 브라우저에서 측정했습니다. 출력 글자를 최종 자리에 먼저 놓고 원형까지의 역변환을 계산한 다음, 애니메이션이 시작되면 변환을 0으로 되돌리는 FLIP 방식입니다. 같은 글자가 두 번 쓰여도 같은 원형에서 각각 복제되어 나오는 것처럼 보입니다.
색은 추가하지 않았습니다. 다크 모드에서는 미색과 낮은 농도의 회색, 라이트 모드에서는 순백 배경과 차콜만 사용했습니다. 모바일에서는 격자 크기를 줄이고 숫자판이 겹치지 않도록 두 줄 사이의 간격만 조금 늘렸습니다. 모션 축소 설정이 켜진 환경에서는 인트로를 표시하지 않습니다.
다시 보기 버튼도 인트로의 일부였습니다
처음에는 새로고침마다 인트로가 나왔습니다. 만든 사람은 계속 보고 싶지만 방문자에게는 금방 부담이 됩니다. 지금은 로컬 스토리지에 버전과 본 시각을 저장해 같은 브라우저에서는 7일에 한 번만 자동으로 보여줍니다.
푸터에는 다시 보기 버튼을 남겼습니다. 한동안 React 상태만 초기화해 인트로를 되살렸는데, 페이지 맨 아래에서 누르면 스크롤 복원과 겹치며 화면이 위로 움직이거나 인트로가 늦게 나타났습니다. 다시 보기에서는 인트로 키만 삭제하고 언어별 홈을 새 문서로 여는 방식으로 바꿨습니다. 테마 등 다른 로컬 스토리지 값은 지우지 않습니다.
이번 작업에서 가장 오래 남은 결정은 화려한 효과가 아니었습니다. DUOLABS를 먼저 읽게 하고, 잠깐 멈추고, ASUDO를 보여준 뒤 IT를 얻는 순서였습니다. 아홉 글자라는 제약이 격자와 슬롯, 사용 횟수, 최종 워드마크까지 하나의 규칙으로 묶어 주었습니다.
함께 읽기
- Next.js는 운영에서 멀쩡한데 로컬 개발 서버에서만 UI가 먹통이 되는 이유Next.js 애플리케이션은 운영 빌드가 안정적이면 개발 서버도 같은 방식으로 움직일 것 같지만, 둘은 클라이언트 코드의 수명이 다릅니다. 제가 확인한 환경은 Next.js 16.2.7과 Turbopack이었고, 운영 사이트에서는 잘 눌리던 상단 메뉴가 로컬 개발 서버에서만 간헐적으로 먹통이 됐습니다.
- 스크롤바가 없는데 화면 오른쪽에 빈 여백이 생기는 이유웹 앱의 화면 가장자리는 평소에는 눈에 잘 들어오지 않습니다. 콘텐츠와 배경이 자연스럽게 이어지면 굳이 볼 이유가 없기 때문입니다. 그런데 여러 화면을 확인하던 중 오른쪽 끝에 비어 보이는 세로 띠가 계속 눈에 걸렸습니다. 어떤 화면에서는 나타나고, 어떤 화면에서는 덜 보였습니다.
- 디자인 시안을 웹으로 옮기는 순서: 시맨틱 HTML·토큰·컴포넌트디자인 시안을 웹으로 옮길 때 핵심은 픽셀을 그대로 복사하는 것이 아니라, 콘텐츠의 의미와 반복 규칙을 브라우저가 이해할 수 있는 구조로 번역하는 것이다. 이 글에서는 시맨틱 HTML, 디자인 토큰, 컴포넌트, 반응형 규칙을 이용해 시안을 유지보수 가능한 코드로 구현하는 순서를 살펴본다.
- Google 번역을 켰더니 React 앱이 오류 화면으로 바뀐 이유한국어, 영어, 일본어, 중국어를 직접 제공하는 React 랜딩 페이지에서 예상하지 못한 문제가 생겼습니다. Chrome이 띄운 "이 페이지를 번역하시겠습니까?" 제안을 수락하면 번역이 시작되는 듯하다가, 잠시 뒤 사이트의 "일시적인 오류가 발생했습니다" 화면으로 바뀌었습니다.
- 데스크톱 AI 화면을 모바일에서 과감히 제거한 이유데스크톱에서 잘 작동하는 AI 인터페이스를 모바일 화면에 그대로 줄이면 기능은 남지만 경험은 쉽게 무너집니다. 사이드바, 대화, 참고 문헌을 동시에 보여주는 3단 구조는 넓은 화면에서는 강력하지만 작은 화면에서는 탐색과 스크롤이 서로 경쟁합니다.