feat: rotating headline with typing effect

- Add typing animation for hero headlines
- Headlines: 거뜬합니다, 최적의 컨디션, 멈추지 않습니다, 아시아 전역 커버, AI가 합니다
- Remove progress dots for cleaner UI
- Update regions: 도쿄 · 오사카 · 서울 · 싱가포르

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
kappa
2026-01-30 08:04:53 +09:00
parent cec96bc3b2
commit 9473ecd204

View File

@@ -3,11 +3,11 @@
<head> <head>
<meta charset="utf-8"/> <meta charset="utf-8"/>
<meta content="width=device-width, initial-scale=1.0" name="viewport"/> <meta content="width=device-width, initial-scale=1.0" name="viewport"/>
<title>Anvil Hosting - 개발자를 위한 컨테이너 클라우드</title> <title>Anvil Hosting - 엔지니어가 관리하는 Linux 서버</title>
<!-- SEO Meta Tags --> <!-- SEO Meta Tags -->
<meta name="description" content="Incus/LXD 기반 초경량 컨테이너 호스팅. VM 오버헤드 없이 네이티브 성능을 제공하며, n8n, Ansible 자동화 파이프라인과 즉시 연동됩니다."> <meta name="description" content="엔지니어가 직접 튜닝한 Linux 서버. 웹, DB, API, 게임서버 뭐든 돌립니다. 고객의 문제가 해결될 때까지, 우리는 멈추지 않습니다.">
<meta name="keywords" content="컨테이너 호스팅, LXD, Incus, 클라우드 서버, VPS, 도쿄 서버, 서울 서버, 개발자 호스팅"> <meta name="keywords" content="Linux 서버, 클라우드 서버, VPS, 도쿄 서버, 서울 서버, 관리형 호스팅, 서버 호스팅">
<meta name="author" content="Anvil Hosting"> <meta name="author" content="Anvil Hosting">
<meta name="robots" content="index, follow"> <meta name="robots" content="index, follow">
<link rel="canonical" href="https://hosting.anvil.it.com"> <link rel="canonical" href="https://hosting.anvil.it.com">
@@ -15,8 +15,8 @@
<!-- Open Graph --> <!-- Open Graph -->
<meta property="og:type" content="website"> <meta property="og:type" content="website">
<meta property="og:url" content="https://hosting.anvil.it.com"> <meta property="og:url" content="https://hosting.anvil.it.com">
<meta property="og:title" content="Anvil Hosting - 개발자를 위한 컨테이너 클라우드"> <meta property="og:title" content="Anvil Hosting - 엔지니어가 관리하는 Linux 서버">
<meta property="og:description" content="Incus/LXD 기반 초경량 컨테이너 호스팅. 네이티브 성능과 자동화 파이프라인을 경험하세요."> <meta property="og:description" content="엔지니어가 직접 튜닝한 Linux 서버. 고객의 문제가 해결될 때까지, 우리는 멈추지 않습니다.">
<meta property="og:locale" content="ko_KR"> <meta property="og:locale" content="ko_KR">
<!-- Favicon --> <!-- Favicon -->
@@ -124,17 +124,14 @@
/_/ \_\_| \_| \_/ |___|_____| /_/ \_\_| \_| \_/ |___|_____|
</pre> </pre>
<!-- Main Headline --> <!-- Main Headline with Rotation -->
<div class="space-y-4 max-w-4xl mt-4"> <div class="space-y-6 max-w-4xl mt-4" x-data="headlineRotator()">
<h1 class="text-2xl md:text-4xl lg:text-5xl font-display font-bold text-white tracking-tight leading-tight"> <div class="min-h-[120px] md:min-h-[160px] lg:min-h-[200px] flex flex-col justify-center">
<span class="text-terminal-muted mr-2">&gt;</span>Incus/LXD 기반<br/> <h1 class="text-2xl md:text-4xl lg:text-5xl font-display font-bold text-white tracking-tight leading-tight">
<span class="text-terminal-muted mr-2">&gt;</span>초경량 컨테이너 호스팅<span class="text-primary cursor-blink text-3xl md:text-5xl align-middle ml-1"></span> <span class="text-terminal-muted mr-2">&gt;</span><span x-text="displayedLine1"></span><span x-show="isTypingLine1" class="text-primary cursor-blink">_</span><br/>
</h1> <span class="text-terminal-muted mr-2">&gt;</span><span class="text-primary" x-text="displayedLine2"></span><span x-show="isTypingLine2 || (!isTypingLine1 && !isTypingLine2)" class="text-primary cursor-blink">_</span>
<p class="text-terminal-muted text-base md:text-lg max-w-2xl border-l-2 border-terminal-border pl-4 mt-4"> </h1>
# VM 오버헤드 없이 네이티브 성능<br/> </div>
# 하이퍼바이저 없는 순수 Linux 컨테이너<br/>
# 도쿄 · 서울 · 싱가포르 · 홍콩 리전
</p>
</div> </div>
<!-- Typing Carousel --> <!-- Typing Carousel -->
@@ -375,6 +372,96 @@
<!-- Alpine.js --> <!-- Alpine.js -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script> <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.14.3/dist/cdn.min.js"></script>
<script> <script>
function headlineRotator() {
return {
headlines: [
{ line1: '웹, DB, API, 게임서버', line2: '거뜬합니다' },
{ line1: '엔지니어가 튜닝한', line2: '최적의 컨디션' },
{ line1: '고객의 문제가 해결될 때까지', line2: '우리는 멈추지 않습니다' },
{ line1: '도쿄 · 오사카 · 서울 · 싱가포르', line2: '아시아 전역 커버' },
{ line1: '복잡한 서버 관리는 이제 그만', line2: '지금부터 AI가 합니다' },
],
currentIndex: 0,
progress: 0,
displayedLine1: '',
displayedLine2: '',
isTypingLine1: true,
isTypingLine2: false,
typingId: null,
progressId: null,
init() {
this.startTyping();
},
startTyping() {
this.displayedLine1 = '';
this.displayedLine2 = '';
this.isTypingLine1 = true;
this.isTypingLine2 = false;
this.progress = 0;
if (this.typingId) clearInterval(this.typingId);
if (this.progressId) clearInterval(this.progressId);
const line1 = this.headlines[this.currentIndex].line1;
const line2 = this.headlines[this.currentIndex].line2;
let charIndex = 0;
// Type line 1
this.typingId = setInterval(() => {
if (charIndex < line1.length) {
this.displayedLine1 = line1.substring(0, charIndex + 1);
charIndex++;
} else {
clearInterval(this.typingId);
this.isTypingLine1 = false;
this.isTypingLine2 = true;
charIndex = 0;
// Type line 2
this.typingId = setInterval(() => {
if (charIndex < line2.length) {
this.displayedLine2 = line2.substring(0, charIndex + 1);
charIndex++;
} else {
clearInterval(this.typingId);
this.isTypingLine2 = false;
this.startProgress();
}
}, 60);
}
}, 60);
},
startProgress() {
this.progress = 0;
const duration = 3000;
const step = 100 / (duration / 50);
this.progressId = setInterval(() => {
this.progress += step;
if (this.progress >= 100) {
clearInterval(this.progressId);
this.next();
}
}, 50);
},
next() {
this.currentIndex = (this.currentIndex + 1) % this.headlines.length;
this.startTyping();
},
goTo(index) {
if (this.typingId) clearInterval(this.typingId);
if (this.progressId) clearInterval(this.progressId);
this.currentIndex = index;
this.startTyping();
}
};
}
function typingCarousel() { function typingCarousel() {
return { return {
commands: [ commands: [