feat: build company introduction webpage

This commit is contained in:
2026-06-24 10:41:31 +09:00
commit edacb08141
52 changed files with 2080 additions and 0 deletions

14
README.md Normal file
View File

@@ -0,0 +1,14 @@
# CompanyIntroduction
컴트로피 회사소개서 PPTX 내용을 기반으로 만든 정적 웹 소개 페이지입니다.
## 구성
- `index.html`: 페이지 마크업과 회사소개 콘텐츠
- `styles.css`: 시네마틱 원페이지 UI 스타일
- `script.js`: 로더, 스크롤 리빌, 모바일 메뉴, 사업 사례 탭
- `assets/media/`: PPTX에서 추출 및 웹 최적화한 이미지 자산
## 실행
브라우저에서 `index.html`을 열면 바로 확인할 수 있습니다.

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 779 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 162 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
assets/media/world-map.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

363
index.html Normal file
View File

@@ -0,0 +1,363 @@
<!doctype html>
<html lang="ko" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#070706">
<meta
name="description"
content="컴트로피 회사소개 웹페이지. 방송 그래픽, 실시간 데이터, AI 솔루션, 웹/앱 개발 역량 소개."
>
<title>컴트로피 | Total IT Service</title>
<script>
document.documentElement.classList.remove("no-js");
document.documentElement.classList.add("js");
</script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
href="https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@600;700;800;900&family=IBM+Plex+Mono:wght@500;600&family=Noto+Sans+KR:wght@400;500;700;800;900&display=swap"
rel="stylesheet"
>
<link rel="stylesheet" href="styles.css">
</head>
<body class="is-loading">
<div class="loader" aria-hidden="true">
<div class="loader__inner">
<div class="loader__top">
<strong>COMTROPY</strong>
<span id="loaderValue">00</span>
</div>
<div class="loader__track"><span id="loaderBar"></span></div>
<div class="loader__foot">
<span>Total IT Service</span>
<span>Broadcast Data Systems</span>
</div>
</div>
</div>
<div class="cursor" aria-hidden="true"></div>
<header class="site-header" id="siteHeader">
<div class="header__inner">
<a class="brand" href="#top" aria-label="컴트로피 홈">
<span class="brand__mark">C</span>
<span>COMTROPY</span>
</a>
<nav class="primary-nav" aria-label="주요 메뉴">
<a href="#about">회사</a>
<a href="#clients">고객사</a>
<a href="#services">사업</a>
<a href="#contact">문의</a>
</nav>
<a class="header__contact" href="mailto:ecoropy@naver.com">
<i data-lucide="send"></i>
<span>CONTACT</span>
</a>
<button class="menu-toggle" type="button" aria-label="메뉴 열기" aria-expanded="false">
<i data-lucide="menu"></i>
</button>
</div>
<div class="scroll-progress" aria-hidden="true"></div>
</header>
<div class="mobile-panel" id="mobilePanel" aria-hidden="true">
<nav aria-label="모바일 메뉴">
<a href="#about"><span>01</span>회사</a>
<a href="#clients"><span>02</span>고객사</a>
<a href="#services"><span>03</span>사업</a>
<a href="#contact"><span>04</span>문의</a>
</nav>
<p>서울특별시 금천구 서부샛길 606 대성지식산업센터 B동 1601호</p>
</div>
<main id="top">
<section class="hero section" aria-labelledby="heroTitle">
<div class="hero__media" aria-hidden="true">
<img src="assets/media/election-seat-map.webp" alt="">
</div>
<div class="hero__shade" aria-hidden="true"></div>
<div class="shell hero__inner">
<div class="hero__copy reveal">
<p class="eyebrow">Company Introduction</p>
<h1 id="heroTitle">고객과 함께<br>성장하는<br>Total IT Service</h1>
<p class="hero__lead">
컴트로피는 실시간 방송 자막 송출 시스템, 방송 TV Graphic 솔루션,
웹/앱 구축과 AI 솔루션을 개발하는 IT 솔루션 전문기업입니다.
</p>
<div class="hero__actions">
<a class="button button--hot" href="#services">
<span>주요 사업 보기</span>
<i data-lucide="arrow-up-right"></i>
</a>
<a class="button" href="#contact">
<span>문의하기</span>
<i data-lucide="mail"></i>
</a>
</div>
</div>
<aside class="hero__console reveal" data-delay="1" aria-label="핵심 역량">
<div class="console__top">
<span>LIVE SYSTEM</span>
<strong>ON AIR</strong>
</div>
<div class="signal-grid">
<span>Election</span>
<span>Home Shopping</span>
<span>Finance</span>
<span>Sports</span>
<span>Virtual Graphic</span>
<span>AI Vision</span>
</div>
<img src="assets/media/election-candidate-screen.webp" alt="선거방송 후보자 득표 그래픽 화면">
</aside>
</div>
</section>
<section class="ticker" aria-label="주요 분야">
<div class="ticker__track">
<span>Broadcast TV Graphic</span>
<span>Real-time Data</span>
<span>AI Learning Solution</span>
<span>Web Contents</span>
<span>Database System</span>
<span>Sports International Signal</span>
<span>Broadcast TV Graphic</span>
<span>Real-time Data</span>
<span>AI Learning Solution</span>
</div>
</section>
<section class="section about" id="about" aria-labelledby="aboutTitle">
<div class="shell about__grid">
<div class="section-heading reveal">
<p class="eyebrow">01 / About</p>
<h2 id="aboutTitle">고객 감동 실현을 기업의 사명으로 삼습니다.</h2>
</div>
<div class="about__body reveal" data-delay="1">
<p>
최고의 기술력과 서비스를 지향하며 고객 중심의 사업경쟁력을 강화합니다.
핵심 서비스 분야의 품질을 보장하고, 고객의 가치 향상을 극대화할 수
있도록 끊임없이 개선합니다.
</p>
<div class="value-strip" aria-label="핵심 가치">
<strong>Best People</strong>
<strong>Best Technical</strong>
<strong>Best Company</strong>
</div>
</div>
</div>
<div class="shell mission-grid">
<article class="mission-panel reveal">
<span>Vision</span>
<h3>고객을 선도하는 창조적 리더상 수립</h3>
<p>
새로운 IT 환경의 방향을 제시하고 IT 전문회사로 성장하는 미래가치,
자기혁신의 가치, 창조적 도전의 가치를 실현합니다.
</p>
</article>
<article class="mission-panel mission-panel--accent reveal" data-delay="1">
<span>Mission</span>
<h3>고객과 함께 성장하는 Total IT Service 전문기업</h3>
<p>
고객을 가족처럼 대하고, 미래지향적인 기술 혁신과 신뢰경영을 바탕으로
고객과 가치를 공유하는 회사를 만듭니다.
</p>
</article>
</div>
</section>
<section class="section intro-band" aria-label="회사 일반현황">
<div class="shell intro-band__grid">
<div class="intro-band__image reveal">
<img src="assets/media/digital-network.png" alt="디지털 네트워크 그래픽">
</div>
<div class="intro-band__copy reveal" data-delay="1">
<p class="eyebrow">Company Profile</p>
<h2>방송사의 기술 연구소 역할을 대행하는 개발 파트너</h2>
<p>
선거방송, 증권, 홈쇼핑, 스포츠와 게임 방송의 자막 송출 솔루션을
제공하고, 실시간 데이터 기반 방송 그래픽과 AI 솔루션, 웹 사이트 구축
사업역량을 강화하고 있습니다.
</p>
<dl class="profile-list">
<div>
<dt>사업 분야</dt>
<dd>소프트웨어 개발 및 공급, 방송 TV Graphic 솔루션, 웹 콘텐츠 개발</dd>
</div>
<div>
<dt>위치</dt>
<dd>서울특별시 금천구 서부샛길 606 대성지식산업센터 B동 1601호</dd>
</div>
</dl>
</div>
</div>
</section>
<section class="section clients" id="clients" aria-labelledby="clientsTitle">
<div class="shell section-heading section-heading--wide reveal">
<p class="eyebrow">02 / Clients</p>
<h2 id="clientsTitle">방송, 스포츠, 커머스, 게임 산업의 현장과 함께했습니다.</h2>
</div>
<div class="shell logo-grid reveal" data-delay="1">
<figure><img src="assets/media/client-01-kpga.png" alt="KPGA"></figure>
<figure><img src="assets/media/client-02-ktv.png" alt="KTV 국민방송"></figure>
<figure><img src="assets/media/client-03-kt-alpha.png" alt="KT 알파 쇼핑"></figure>
<figure><img src="assets/media/client-04-sk-store.png" alt="SK 스토아"></figure>
<figure><img src="assets/media/client-05-wbdg.png" alt="WBDG"></figure>
<figure><img src="assets/media/client-06-ytn.png" alt="YTN"></figure>
<figure><img src="assets/media/client-07-maekyung-tv.png" alt="매일경제TV"></figure>
<figure><img src="assets/media/client-08-yonhapnews-tv.png" alt="연합뉴스TV"></figure>
<figure><img src="assets/media/client-09-etdaily-tv.png" alt="이데일리TV"></figure>
<figure><img src="assets/media/client-10-com2us.png" alt="Com2us"></figure>
<figure><img src="assets/media/client-11-tomato-securities.png" alt="토마토증권통"></figure>
<figure><img src="assets/media/client-12-shinsegae-shopping.png" alt="신세계 쇼핑"></figure>
<figure><img src="assets/media/client-13-mbc-cni.png" alt="MBC C&amp;I"></figure>
<figure><img src="assets/media/client-14-mbc.png" alt="MBC"></figure>
<figure><img src="assets/media/client-15-riot-games.png" alt="Riot Games"></figure>
<figure><img src="assets/media/client-16-snuh.png" alt="서울대학교병원"></figure>
</div>
</section>
<section class="section services" id="services" aria-labelledby="servicesTitle">
<div class="shell section-heading section-heading--wide reveal">
<p class="eyebrow">03 / Business</p>
<h2 id="servicesTitle">실시간 데이터를 화면 위의 정확한 언어로 바꿉니다.</h2>
</div>
<div class="shell service-grid">
<article class="service-card reveal">
<span>01</span>
<h3>방송 그래픽 자막 송출 솔루션</h3>
<p>선거방송, 홈쇼핑, 증권, 스포츠와 게임 데이터를 방송 그래픽으로 연결합니다.</p>
</article>
<article class="service-card reveal" data-delay="1">
<span>02</span>
<h3>국제신호 제작</h3>
<p>아시안게임, 동남아시안게임, 월드컵 등 국제경기 중계의 IS 제작 경험을 보유합니다.</p>
</article>
<article class="service-card reveal" data-delay="2">
<span>03</span>
<h3>AI 솔루션 연구 개발</h3>
<p>딥러닝 기반 영상 분석과 거리 측정 시스템 등 현장형 AI 솔루션을 개발합니다.</p>
</article>
<article class="service-card reveal">
<span>04</span>
<h3>데이터베이스 시스템 구축</h3>
<p>실시간 데이터 연계, API, 데이터 송수신 프로그램과 방송 송출 서버를 설계합니다.</p>
</article>
<article class="service-card reveal" data-delay="1">
<span>05</span>
<h3>웹 사이트 / 앱 개발</h3>
<p>방송 운영 시스템과 연동되는 웹 페이지, 모바일 앱, 관리 도구를 구현합니다.</p>
</article>
<article class="service-card reveal" data-delay="2">
<span>06</span>
<h3>버추얼 그래픽 시스템</h3>
<p>Unreal Engine, Unity 기반 VR/AR 시스템과 실시간 3D 그래픽 처리를 제공합니다.</p>
</article>
</div>
</section>
<section class="section case-lab" aria-labelledby="caseTitle">
<div class="shell case-lab__head reveal">
<div>
<p class="eyebrow">Project Fields</p>
<h2 id="caseTitle">현장에서 검증된 여섯 가지 솔루션</h2>
</div>
<p>
데이터 연동, 그래픽 송출, AI 분석, 운영 UI까지 현장 흐름에 맞춰 설계합니다.
</p>
</div>
<div class="shell case-lab__grid">
<div class="case-tabs reveal" role="tablist" aria-label="프로젝트 분야">
<button class="is-active" type="button" role="tab" aria-selected="true" data-case="election">
<i data-lucide="vote"></i><span>선거방송</span>
</button>
<button type="button" role="tab" aria-selected="false" data-case="virtual">
<i data-lucide="box"></i><span>버추얼 그래픽</span>
</button>
<button type="button" role="tab" aria-selected="false" data-case="finance">
<i data-lucide="chart-candlestick"></i><span>경제 방송</span>
</button>
<button type="button" role="tab" aria-selected="false" data-case="ai">
<i data-lucide="scan-search"></i><span>AI 학습</span>
</button>
<button type="button" role="tab" aria-selected="false" data-case="shopping">
<i data-lucide="shopping-bag"></i><span>홈쇼핑</span>
</button>
<button type="button" role="tab" aria-selected="false" data-case="sports">
<i data-lucide="trophy"></i><span>스포츠 TVG</span>
</button>
</div>
<article class="case-stage reveal" data-delay="1" aria-live="polite">
<div class="case-stage__media">
<img id="caseImage" src="assets/media/election-candidate-screen.webp" alt="선거방송 후보자 득표 그래픽 화면">
<div class="case-stage__thumbs" id="caseThumbs"></div>
</div>
<div class="case-stage__copy">
<p class="case-stage__kicker" id="caseKicker">2.1 선거방송</p>
<h3 id="caseName">선거방송 데이터 방송 그래픽 솔루션 개발</h3>
<p id="caseDescription">
선관위 데이터와 방송 그래픽을 실시간으로 연동해 자막 송출 시스템을 구성합니다.
</p>
<ul id="caseBullets"></ul>
</div>
</article>
</div>
</section>
<section class="section sports-system" aria-labelledby="systemTitle">
<div class="sports-system__image reveal">
<img src="assets/media/sports-tvgraphic-console.webp" alt="스포츠 TV 그래픽 운영 콘솔">
</div>
<div class="shell sports-system__content">
<div class="section-heading reveal">
<p class="eyebrow">Sports TV Graphic</p>
<h2 id="systemTitle">데이터 인터페이스부터 사용자 중심 Output까지</h2>
</div>
<div class="system-list reveal" data-delay="1">
<div><strong>Live Data</strong><span>자막시스템에서 사용 가능한 형태로 변환</span></div>
<div><strong>HD/UHD</strong><span>고해상도 CG 제작과 송출 환경 대응</span></div>
<div><strong>IS 제작</strong><span>국제경기 중계의 International Signal 제작</span></div>
<div><strong>Design</strong><span>3D/2D Cut, 애니메이션, 특수 효과 적용</span></div>
<div><strong>Custom UI</strong><span>운영자 중심 설계와 커스터마이징</span></div>
<div><strong>All Sports</strong><span>구기, 투기, 계측 종목 등 다양한 종목 구성</span></div>
</div>
</div>
</section>
<section class="section contact" id="contact" aria-labelledby="contactTitle">
<div class="shell contact__grid">
<div class="contact__copy reveal">
<p class="eyebrow">04 / Contact</p>
<h2 id="contactTitle">방송 현장의 데이터를 안정적인 화면으로 연결합니다.</h2>
<p>
실시간 송출 시스템, 방송 그래픽, AI 영상 분석, 웹/앱 개발이 필요한 프로젝트를
컴트로피와 함께 구체화해보세요.
</p>
</div>
<address class="contact-card reveal" data-delay="1">
<a href="tel:010-9008-2329"><i data-lucide="phone"></i><span>010-9008-2329</span></a>
<a href="mailto:ecoropy@naver.com"><i data-lucide="mail"></i><span>ecoropy@naver.com</span></a>
<p><i data-lucide="map-pin"></i><span>서울특별시 금천구 서부샛길 606 대성지식산업센터 B동 1601호</span></p>
</address>
</div>
</section>
</main>
<footer class="site-footer">
<div class="shell">
<strong>COMTROPY</strong>
<span>Best People, Best Technical, Best Company</span>
</div>
</footer>
<script src="https://unpkg.com/lucide@latest/dist/umd/lucide.min.js"></script>
<script src="script.js"></script>
</body>
</html>

236
script.js Normal file
View File

@@ -0,0 +1,236 @@
const caseData = {
election: {
kicker: "2.1 선거방송",
title: "선거방송 데이터 방송 그래픽 솔루션 개발",
description: "선관위 데이터와 방송 그래픽을 실시간으로 연동해 자막 송출 시스템을 구성합니다.",
bullets: [
"선관위 데이터 실시간 연동 코드 적용",
"데이터 스케줄러와 송출 컨트롤러 시스템 개발",
"방송 그래픽과 데이터 연동을 통한 실시간 자막 송출"
],
images: [
{ src: "assets/media/election-candidate-screen.webp", alt: "선거방송 후보자 득표 그래픽 화면" },
{ src: "assets/media/election-seat-map.webp", alt: "선거방송 의석 현황 그래픽 화면" },
{ src: "assets/media/election-region-map.webp", alt: "선거방송 전국 판세 지도 그래픽" }
]
},
virtual: {
kicker: "2.2 버추얼 그래픽 시스템",
title: "버추얼 그래픽 솔루션 개발",
description: "Unreal Engine과 Unity를 활용해 VR, AR 기반의 실시간 3D 그래픽 시스템을 개발합니다.",
bullets: [
"Unreal Engine 기반 VR/AR 시스템 개발",
"실시간 데이터 3D 그래픽 처리 시스템 적용",
"Unity 활용 영상 콘텐츠 제작"
],
images: [
{ src: "assets/media/virtual-election-studio.webp", alt: "버추얼 선거방송 스튜디오 그래픽" },
{ src: "assets/media/virtual-candidate-wall.webp", alt: "버추얼 후보자 데이터 월" },
{ src: "assets/media/virtual-debate-wall.webp", alt: "버추얼 토론 방송 그래픽 월" }
]
},
finance: {
kicker: "2.3 데이터베이스 / 경제 방송",
title: "증권 데이터 및 경제 방송 송출 그래픽 시스템",
description: "코스콤 데이터와 해외 지수 데이터를 연계해 방송 송출 그래픽과 API 서버를 구현합니다.",
bullets: [
"코스콤 데이터와 해외 지수 연계 데이터베이스 서버 구축",
"실시간 그래픽 연계 데이터 송수신 프로그램 개발",
"REST 서버 API 구현 및 방송 송출 시스템 적용"
],
images: [
{ src: "assets/media/finance-chart.webp", alt: "경제 방송 주가 차트 그래픽" },
{ src: "assets/media/finance-index.webp", alt: "경제 방송 지수 그래픽" },
{ src: "assets/media/finance-db-console.webp", alt: "경제 방송 데이터베이스 콘솔" }
]
},
ai: {
kicker: "2.4 AI 학습 솔루션",
title: "AI 기반 거리 측정 시스템",
description: "KPGA 공식 기록에 사용되는 그린 홀 컵 간 거리 측정 솔루션을 개발했습니다.",
bullets: [
"CUDA 기반 딥러닝 모델 학습",
"카메라 영상 신호 수신 후 공 위치와 좌표 변환",
"골프 중계와 기록 환경에 맞춘 AI 거리 측정"
],
images: [
{ src: "assets/media/ai-distance-result.webp", alt: "AI 기반 거리 측정 결과 화면" },
{ src: "assets/media/ai-training-green.webp", alt: "골프 그린 AI 학습 화면" },
{ src: "assets/media/ai-detection-console.webp", alt: "AI 영상 분석 콘솔 화면" }
]
},
shopping: {
kicker: "2.5 홈쇼핑 송출 시스템",
title: "홈쇼핑 자동화 송출 시스템 / 라이브 톡",
description: "송출 스케줄과 원격 제어, 모바일 연동을 포함한 홈쇼핑 방송 운영 시스템을 개발합니다.",
bullets: [
"송출 스케줄 관리 데이터 송수신 모듈 개발",
"홈쇼핑 송출 프로그램 원격제어 로컬/모바일 연동",
"웹 페이지와 앱을 활용한 실시간 방송 데이터 송출"
],
images: [
{ src: "assets/media/shopping-control-dashboard.webp", alt: "홈쇼핑 송출 제어 대시보드" },
{ src: "assets/media/shopping-live-output.webp", alt: "홈쇼핑 라이브 방송 송출 화면" },
{ src: "assets/media/mobile-live-talk.webp", alt: "홈쇼핑 모바일 라이브 톡 화면" }
]
},
sports: {
kicker: "2.6 스포츠 TV Graphic",
title: "스포츠 / 게임 데이터 솔루션 송출 시스템 개발",
description: "Live Data를 자막시스템에서 사용 가능한 형태로 변환하고 다양한 종목의 TVG 시스템을 제작합니다.",
bullets: [
"HD/UHD급 CG 제작과 국제신호 제작",
"3D/2D Cut, 애니메이션 등 특수 효과 적용",
"구기, 투기, 계측 종목 등 다양한 스포츠 TVG 구성"
],
images: [
{ src: "assets/media/sports-game-result.webp", alt: "게임 결과 방송 그래픽" },
{ src: "assets/media/sports-player-profile.webp", alt: "선수 프로필 방송 그래픽" },
{ src: "assets/media/football-scorebug.webp", alt: "축구 스코어버그 방송 그래픽" }
]
}
};
const body = document.body;
const header = document.getElementById("siteHeader");
const mobilePanel = document.getElementById("mobilePanel");
const menuToggle = document.querySelector(".menu-toggle");
const cursor = document.querySelector(".cursor");
const loaderBar = document.getElementById("loaderBar");
const loaderValue = document.getElementById("loaderValue");
const caseImage = document.getElementById("caseImage");
const caseKicker = document.getElementById("caseKicker");
const caseName = document.getElementById("caseName");
const caseDescription = document.getElementById("caseDescription");
const caseBullets = document.getElementById("caseBullets");
const caseThumbs = document.getElementById("caseThumbs");
const navLinks = [...document.querySelectorAll(".primary-nav a")];
let loaderProgress = 0;
const loaderTimer = window.setInterval(() => {
loaderProgress = Math.min(loaderProgress + Math.ceil(Math.random() * 12), 100);
loaderBar.style.width = `${loaderProgress}%`;
loaderValue.textContent = String(loaderProgress).padStart(2, "0");
if (loaderProgress >= 100) {
window.clearInterval(loaderTimer);
window.setTimeout(() => {
body.classList.remove("is-loading");
body.classList.add("is-ready");
}, 220);
}
}, 55);
const updateScrollState = () => {
const scrollTop = window.scrollY || document.documentElement.scrollTop;
const scrollable = document.documentElement.scrollHeight - window.innerHeight;
const progress = scrollable > 0 ? (scrollTop / scrollable) * 100 : 0;
header.classList.toggle("is-scrolled", scrollTop > 20);
header.style.setProperty("--page-progress", `${progress}%`);
let currentHref = navLinks[0]?.getAttribute("href");
navLinks.forEach(link => {
const target = document.querySelector(link.getAttribute("href"));
if (target && target.getBoundingClientRect().top <= window.innerHeight * 0.45) {
currentHref = link.getAttribute("href");
}
});
navLinks.forEach(link => {
link.setAttribute("aria-current", link.getAttribute("href") === currentHref ? "true" : "false");
});
};
window.addEventListener("scroll", updateScrollState, { passive: true });
window.addEventListener("resize", updateScrollState);
updateScrollState();
const revealObserver = new IntersectionObserver(
entries => {
entries.forEach(entry => {
if (entry.isIntersecting) {
entry.target.classList.add("in-view");
revealObserver.unobserve(entry.target);
}
});
},
{ threshold: 0.16 }
);
document.querySelectorAll(".reveal").forEach(element => revealObserver.observe(element));
const setMenuOpen = open => {
menuToggle.setAttribute("aria-expanded", String(open));
menuToggle.setAttribute("aria-label", open ? "메뉴 닫기" : "메뉴 열기");
mobilePanel.classList.toggle("is-open", open);
mobilePanel.setAttribute("aria-hidden", String(!open));
menuToggle.innerHTML = `<i data-lucide="${open ? "x" : "menu"}"></i>`;
if (window.lucide) window.lucide.createIcons();
};
if (menuToggle) {
menuToggle.addEventListener("click", () => {
const open = menuToggle.getAttribute("aria-expanded") !== "true";
setMenuOpen(open);
});
}
mobilePanel.querySelectorAll("a").forEach(link => {
link.addEventListener("click", () => setMenuOpen(false));
});
const renderCase = (key, imageIndex = 0) => {
const data = caseData[key];
const image = data.images[imageIndex];
caseImage.src = image.src;
caseImage.alt = image.alt;
caseKicker.textContent = data.kicker;
caseName.textContent = data.title;
caseDescription.textContent = data.description;
caseBullets.innerHTML = data.bullets.map(item => `<li>${item}</li>`).join("");
caseThumbs.innerHTML = data.images
.map(
(item, index) => `
<button type="button" class="${index === imageIndex ? "is-active" : ""}" data-case-thumb="${index}" aria-label="${item.alt}">
<img src="${item.src}" alt="">
</button>
`
)
.join("");
caseThumbs.querySelectorAll("button").forEach(button => {
button.addEventListener("click", () => renderCase(key, Number(button.dataset.caseThumb)));
});
};
document.querySelectorAll(".case-tabs button").forEach(button => {
button.addEventListener("click", () => {
document.querySelectorAll(".case-tabs button").forEach(item => {
item.classList.remove("is-active");
item.setAttribute("aria-selected", "false");
});
button.classList.add("is-active");
button.setAttribute("aria-selected", "true");
renderCase(button.dataset.case);
});
});
renderCase("election");
if (window.matchMedia("(pointer: fine)").matches && cursor) {
window.addEventListener("pointermove", event => {
cursor.style.transform = `translate3d(${event.clientX}px, ${event.clientY}px, 0) translate(-50%, -50%)`;
cursor.classList.add("is-visible");
});
document.querySelectorAll("a, button").forEach(element => {
element.addEventListener("pointerenter", () => cursor.classList.add("is-active"));
element.addEventListener("pointerleave", () => cursor.classList.remove("is-active"));
});
}
window.addEventListener("keydown", event => {
if (event.key === "Escape") setMenuOpen(false);
});
if (window.lucide) {
window.lucide.createIcons();
}

1467
styles.css Normal file

File diff suppressed because it is too large Load Diff