commit 39fefc5834381bd7b3fd311fba235333d98f3fcd Author: zenn Date: Mon Sep 21 13:52:16 2026 +0900 Build MOBIPINTECH company website diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..ab6dca1 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,6 @@ +assets/images/automotive/** filter=lfs diff=lfs merge=lfs -text +assets/images/robotics/** filter=lfs diff=lfs merge=lfs -text +assets/images/solution/** filter=lfs diff=lfs merge=lfs -text +assets/images/si/** filter=lfs diff=lfs merge=lfs -text +assets/images/patents/** filter=lfs diff=lfs merge=lfs -text +assets/docs/*.pdf filter=lfs diff=lfs merge=lfs -text diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4f074fd --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store +**/.DS_Store diff --git a/README.md b/README.md new file mode 100644 index 0000000..4ea231f --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# MOBIPINTECH Website + +모비핀테크놀러지 회사 소개 웹사이트입니다. + +## 구성 + +- 정적 HTML, CSS, JavaScript +- PocketBase 기반 문의 접수 +- WebP 기반 기술 역량 이미지 최적화 + +## 이미지 갱신 + +기술 역량 원본 이미지를 변경한 뒤 다음 명령으로 웹용 이미지와 SEO 콘텐츠를 갱신합니다. + +```bash +node scripts/generate-capability-webp.mjs +node scripts/generate-capability-thumbnails.mjs +node scripts/sync-capabilities-seo.mjs +``` + +WebP 생성에는 `cwebp`가 필요합니다. diff --git a/about.html b/about.html new file mode 100644 index 0000000..2d4a755 --- /dev/null +++ b/about.html @@ -0,0 +1,416 @@ + + + + + + + About · MOBIPINTECH + + + + + + + + + + +
+
+
+

Company Overview

+ +

모비핀테크놀러지

+

+ 모비핀테크놀러지는 스마트 플랫폼과 AI 로봇 개발 경험을 기반으로 + AUTOSAR 전장, 관제 솔루션, 로봇 SW, 웹·앱 SI까지 연결하는 개발 + 조직입니다. +

+
+
+
+
+
회사명
+
주식회사 모비핀테크놀러지
+
+
+
설립일
+
2015년 3월
+
+
+
대표이사
+
권오규
+
+
+
종업원 수
+
40명 (2026년 3월 기준)
+
+
+
주소
+
+ 대구 북구 경대로17길 47, 8층 803호
서울시 강남구 논현로 416 + 운기빌딩 6층 +
+
+
+
+
+ +
+

Integrated Capability

+

경험을 기술로, 기술을 성과로 연결합니다.

+
+
+ + 01 + 전장 + AUTOMOTIVE +
+
+ + 02 + AI/로봇 + AI & ROBOTICS +
+
+ + 03 + 솔루션 + ENTERPRISE SOLUTIONS +
+
+ + 04 + SI + SYSTEMS INTEGRATION +
+
+ +
+ +
+

Growth Track · 2026–2021

+

기술 영역을 확장해 온 성장의 궤적

+
+
+ 2026 +

전장 개발·검증 영역 확장

+
    +
  • HL Klemove 플랫폼 및 Safety Mechanism SW 개발
  • +
  • EB Safety Classic AUTOSAR 멀티코어 포팅·앱 개발
  • +
  • 현대차 BDC 전장 SW 로그 분석·리프로그래밍
  • +
  • SL SBCM & IO 제어기 통합, 기능 SW 개발
  • +
  • SL 전장 램프 및 전동화 제어기 SWE5 통합 검증 용역
  • +
  • SL LDM 제어기 검증 용역
  • +
  • 현대자동차 협력사 등록
  • +
+
+
+ 2025 +

로봇·SI 개발 영역 확장

+
    +
  • 울진군 스카이레일 관제 시스템 개발
  • +
  • SMT 제1공장 설비모니터링 및 관제 MES 개발
  • +
  • 클로봇 치과 진료안내서비스(코디봇) 개발
  • +
  • 국립해양박물관 큐레이팅 봇 개발
  • +
  • 현대위아 해외법인(중국, 멕시코) 구매시스템 웹 표준화
  • +
+
+
+ 2024 +

AUTOSAR 기반 전장 개발 확대

+
    +
  • HL Klemove FCM 제어기 AUTOSAR BSW 개발
  • +
  • JS TECH 공조 STMicro Chorus 제어기 BSW 개발
  • +
  • HL Klemove ADAS DRV 제어기 BSW 개발
  • +
  • 대우전자부품 CCH 제어기 AUTOSAR BSW 컨설팅
  • +
+
+
+ 2023 +

전장 개발 체계 구축

+
    +
  • SL SBCM 개발(Side Body Control Module) 개발
  • +
  • JS TECH ASW 컨설팅
  • +
  • AUTOSAR 기반 APP/SW 설계
  • +
  • AUTOSAR 통합 자동화 플랫폼 개발
  • +
  • ECU 기능 모듈 개발 통합
  • +
+
+
+ 2022 +

자동차 전장 개발 진입

+
    +
  • LG전자 BMW·Honda·Toyota 텔레매틱스 BSP
  • +
  • Qualcomm·MediaTek 모뎀 칩 개발
  • +
  • LG U+·KT 안내로봇 개발
  • +
  • 자동차 전장 AUTOSAR SW 개발
  • +
+
+
+ 2021 +

AI 플랫폼 사업 영역 구축

+
    +
  • 지능형 자동보고 플랫폼 구축
  • +
  • 관리형 독서실 플랫폼 구축
  • +
  • 국제 특허 통합 플랫폼 구축
  • +
  • 전주 시청 대기 환경 모니터링 통합 관제 개발
  • +
  • AJ 셀카 실내촬영 솔루션 개발 및 운영
  • +
  • 현대오토에버 협력사 등록
  • +
  • 현대오토에버 NAVI 개발 협력
  • +
+
+
+
+ +
+

Growth Track · 2020–2003

+

성장의 기반을 쌓아 온 시간

+
+
+ 2020 – 2018 +

솔루션 사업 확장

+
    +
  • SK증권 사내방송 시스템 구축
  • +
  • SK렌터카·K Car 3D 자동촬영 솔루션 구축
  • +
  • 3D 촬영 SW 엔진 및 제어 HW 솔루션 개발
  • +
  • SKT 스마트 트래커 개발
  • +
  • 벤처기업 인증
  • +
+
+
+ 2017 – 2015 +

회사 설립 및 사업 연계

+
    +
  • 신용보증기금 퍼스트펭귄 창업기업 선정
  • +
  • 현대엠엔소프트 내비게이션 SW 협력 개발
  • +
  • 서울버스TV 광고방송 시스템 구축 (IoT 플랫폼 활용)
  • +
  • + 홈플러스 및 롯데마트 매장 광고 시스템 구축 (IoT 플랫폼 활용) +
  • +
  • 갤럭시 6, 6 Edge 용 Mac OS용 Theme Editor 개발
  • +
  • 창업우수기업 표창(대구광역시장)
  • +
  • ㈜모비핀테크놀러지 기업부설연구소 설립
  • +
  • IOT,AI 통합 플랫폼 출시 (VOISO)
  • +
  • ㈜유니트론텍 투자유치
  • +
  • ㈜모비핀테크놀러지 법인 설립
  • +
+
+
+ 2014 – 2003 +

전신 사업 분야

+
    +
  • + SM-V101F유럽파생/CIS/ 서남아/ 중동향 Nucleus 기반 Web UI S/W +
  • +
  • Android 과제 3rd Party Application/ GMS 개발 지원
  • +
  • S-Note3 및 삼성 Android System·App 개발
  • +
  • 미주 CDMA 사업자향 QSC61x5 플랫폼 개발
  • +
  • 삼성전자 무선사업부 CDMA Phone 사업 참여
  • +
+
+
+
+ +
+

Organization

+

조직 구성

+
+
CEO
+
+
+ Corporate Support경영지원실 +
    +
  • 관리팀
  • +
  • 재무팀
  • +
+
+
+ Technology Teams개발실 +
    +
  • 전장개발팀
  • +
  • 솔루션개발팀
  • +
  • AI/로봇 개발팀
  • +
  • SI 개발팀
  • +
+
+
+ Supply Chain ManagementSCM팀 +
+
+ R&D / Future Technology기업부설 연구소 +
+
+
+
+ +
+

Partners

+

협력사

+
+
+ HYUNDAI +
+
+ HYUNDAI AutoEver +
+
+ HYUNDAI WIA +
+
+ SL Corporation +
+
+ K Car +
+
+ SK 증권 +
+
+ SK 네트웍스 +
+
+ LG전자 +
+
+ HL Klemove +
+
+ Unitrontech +
+
+ clobot +
+
+ KB차차차 +
+
+ Wonderful Platform +
+
+ CTR +
+
+
+
+ + + + + + diff --git a/assets/docs/MOBIPIN_회사소개서_20260918.pdf b/assets/docs/MOBIPIN_회사소개서_20260918.pdf new file mode 100644 index 0000000..7b98d1b --- /dev/null +++ b/assets/docs/MOBIPIN_회사소개서_20260918.pdf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9185ff6c56b8d4ce951f297f859d18649a698c93f9b6139b607cc1025a3bcccf +size 16200120 diff --git a/assets/icons/chevron_backward.svg b/assets/icons/chevron_backward.svg new file mode 100644 index 0000000..bcb19a4 --- /dev/null +++ b/assets/icons/chevron_backward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/chevron_forward.svg b/assets/icons/chevron_forward.svg new file mode 100644 index 0000000..6d07d52 --- /dev/null +++ b/assets/icons/chevron_forward.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/keyboard_arrow_down.svg b/assets/icons/keyboard_arrow_down.svg new file mode 100644 index 0000000..3da4f84 --- /dev/null +++ b/assets/icons/keyboard_arrow_down.svg @@ -0,0 +1 @@ + diff --git a/assets/icons/pause.svg b/assets/icons/pause.svg new file mode 100644 index 0000000..4e1ca05 --- /dev/null +++ b/assets/icons/pause.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/play_arrow.svg b/assets/icons/play_arrow.svg new file mode 100644 index 0000000..5cf4892 --- /dev/null +++ b/assets/icons/play_arrow.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/icons/stop.svg b/assets/icons/stop.svg new file mode 100644 index 0000000..f8fb414 --- /dev/null +++ b/assets/icons/stop.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/assets/images-webp/automotive/automotive_01_background.webp b/assets/images-webp/automotive/automotive_01_background.webp new file mode 100644 index 0000000..b9a916d Binary files /dev/null and b/assets/images-webp/automotive/automotive_01_background.webp differ diff --git a/assets/images-webp/automotive/automotive_01_object.webp b/assets/images-webp/automotive/automotive_01_object.webp new file mode 100644 index 0000000..691b871 Binary files /dev/null and b/assets/images-webp/automotive/automotive_01_object.webp differ diff --git a/assets/images-webp/automotive/automotive_02_background.webp b/assets/images-webp/automotive/automotive_02_background.webp new file mode 100644 index 0000000..d149943 Binary files /dev/null and b/assets/images-webp/automotive/automotive_02_background.webp differ diff --git a/assets/images-webp/automotive/automotive_02_object.webp b/assets/images-webp/automotive/automotive_02_object.webp new file mode 100644 index 0000000..4f251d8 Binary files /dev/null and b/assets/images-webp/automotive/automotive_02_object.webp differ diff --git a/assets/images-webp/automotive/automotive_03_background.webp b/assets/images-webp/automotive/automotive_03_background.webp new file mode 100644 index 0000000..08dd907 Binary files /dev/null and b/assets/images-webp/automotive/automotive_03_background.webp differ diff --git a/assets/images-webp/automotive/automotive_03_object.webp b/assets/images-webp/automotive/automotive_03_object.webp new file mode 100644 index 0000000..5c5f81a Binary files /dev/null and b/assets/images-webp/automotive/automotive_03_object.webp differ diff --git a/assets/images-webp/automotive/automotive_04_background.webp b/assets/images-webp/automotive/automotive_04_background.webp new file mode 100644 index 0000000..120d79a Binary files /dev/null and b/assets/images-webp/automotive/automotive_04_background.webp differ diff --git a/assets/images-webp/automotive/automotive_04_object.webp b/assets/images-webp/automotive/automotive_04_object.webp new file mode 100644 index 0000000..4f251d8 Binary files /dev/null and b/assets/images-webp/automotive/automotive_04_object.webp differ diff --git a/assets/images-webp/automotive/automotive_05_background.webp b/assets/images-webp/automotive/automotive_05_background.webp new file mode 100644 index 0000000..6d39f14 Binary files /dev/null and b/assets/images-webp/automotive/automotive_05_background.webp differ diff --git a/assets/images-webp/automotive/automotive_05_object.webp b/assets/images-webp/automotive/automotive_05_object.webp new file mode 100644 index 0000000..f872b14 Binary files /dev/null and b/assets/images-webp/automotive/automotive_05_object.webp differ diff --git a/assets/images-webp/automotive/automotive_06_background.webp b/assets/images-webp/automotive/automotive_06_background.webp new file mode 100644 index 0000000..c5f9e6f Binary files /dev/null and b/assets/images-webp/automotive/automotive_06_background.webp differ diff --git a/assets/images-webp/automotive/automotive_06_object.webp b/assets/images-webp/automotive/automotive_06_object.webp new file mode 100644 index 0000000..21ac709 Binary files /dev/null and b/assets/images-webp/automotive/automotive_06_object.webp differ diff --git a/assets/images-webp/automotive/automotive_07_background.webp b/assets/images-webp/automotive/automotive_07_background.webp new file mode 100644 index 0000000..42bdd0f Binary files /dev/null and b/assets/images-webp/automotive/automotive_07_background.webp differ diff --git a/assets/images-webp/automotive/automotive_07_object.webp b/assets/images-webp/automotive/automotive_07_object.webp new file mode 100644 index 0000000..8118e77 Binary files /dev/null and b/assets/images-webp/automotive/automotive_07_object.webp differ diff --git a/assets/images-webp/automotive/automotive_08_background.webp b/assets/images-webp/automotive/automotive_08_background.webp new file mode 100644 index 0000000..1f4ed51 Binary files /dev/null and b/assets/images-webp/automotive/automotive_08_background.webp differ diff --git a/assets/images-webp/automotive/automotive_08_object.webp b/assets/images-webp/automotive/automotive_08_object.webp new file mode 100644 index 0000000..72ceef5 Binary files /dev/null and b/assets/images-webp/automotive/automotive_08_object.webp differ diff --git a/assets/images-webp/automotive/automotive_09_background.webp b/assets/images-webp/automotive/automotive_09_background.webp new file mode 100644 index 0000000..d2c8b24 Binary files /dev/null and b/assets/images-webp/automotive/automotive_09_background.webp differ diff --git a/assets/images-webp/automotive/automotive_09_object.webp b/assets/images-webp/automotive/automotive_09_object.webp new file mode 100644 index 0000000..700fd2b Binary files /dev/null and b/assets/images-webp/automotive/automotive_09_object.webp differ diff --git a/assets/images-webp/automotive/automotive_10_background.webp b/assets/images-webp/automotive/automotive_10_background.webp new file mode 100644 index 0000000..d261df2 Binary files /dev/null and b/assets/images-webp/automotive/automotive_10_background.webp differ diff --git a/assets/images-webp/patents/patents_01_object.webp b/assets/images-webp/patents/patents_01_object.webp new file mode 100644 index 0000000..f41e5b1 Binary files /dev/null and b/assets/images-webp/patents/patents_01_object.webp differ diff --git a/assets/images-webp/patents/patents_01_object_02.webp b/assets/images-webp/patents/patents_01_object_02.webp new file mode 100644 index 0000000..f7b2446 Binary files /dev/null and b/assets/images-webp/patents/patents_01_object_02.webp differ diff --git a/assets/images-webp/robotics/robotics_01_background.webp b/assets/images-webp/robotics/robotics_01_background.webp new file mode 100644 index 0000000..7efe7ec Binary files /dev/null and b/assets/images-webp/robotics/robotics_01_background.webp differ diff --git a/assets/images-webp/robotics/robotics_01_object.webp b/assets/images-webp/robotics/robotics_01_object.webp new file mode 100644 index 0000000..7db071d Binary files /dev/null and b/assets/images-webp/robotics/robotics_01_object.webp differ diff --git a/assets/images-webp/robotics/robotics_02_background.webp b/assets/images-webp/robotics/robotics_02_background.webp new file mode 100644 index 0000000..8b5f53e Binary files /dev/null and b/assets/images-webp/robotics/robotics_02_background.webp differ diff --git a/assets/images-webp/robotics/robotics_02_object.webp b/assets/images-webp/robotics/robotics_02_object.webp new file mode 100644 index 0000000..6652e5e Binary files /dev/null and b/assets/images-webp/robotics/robotics_02_object.webp differ diff --git a/assets/images-webp/robotics/robotics_03_background.webp b/assets/images-webp/robotics/robotics_03_background.webp new file mode 100644 index 0000000..7c3055b Binary files /dev/null and b/assets/images-webp/robotics/robotics_03_background.webp differ diff --git a/assets/images-webp/robotics/robotics_03_object.webp b/assets/images-webp/robotics/robotics_03_object.webp new file mode 100644 index 0000000..0dfd11e Binary files /dev/null and b/assets/images-webp/robotics/robotics_03_object.webp differ diff --git a/assets/images-webp/robotics/robotics_04_background.webp b/assets/images-webp/robotics/robotics_04_background.webp new file mode 100644 index 0000000..1986a3d Binary files /dev/null and b/assets/images-webp/robotics/robotics_04_background.webp differ diff --git a/assets/images-webp/robotics/robotics_04_object.webp b/assets/images-webp/robotics/robotics_04_object.webp new file mode 100644 index 0000000..e936fe5 Binary files /dev/null and b/assets/images-webp/robotics/robotics_04_object.webp differ diff --git a/assets/images-webp/si/si_01_background.webp b/assets/images-webp/si/si_01_background.webp new file mode 100644 index 0000000..c1fd72c Binary files /dev/null and b/assets/images-webp/si/si_01_background.webp differ diff --git a/assets/images-webp/si/si_01_object.webp b/assets/images-webp/si/si_01_object.webp new file mode 100644 index 0000000..a05b788 Binary files /dev/null and b/assets/images-webp/si/si_01_object.webp differ diff --git a/assets/images-webp/si/si_02_background.webp b/assets/images-webp/si/si_02_background.webp new file mode 100644 index 0000000..4d13485 Binary files /dev/null and b/assets/images-webp/si/si_02_background.webp differ diff --git a/assets/images-webp/si/si_02_object.webp b/assets/images-webp/si/si_02_object.webp new file mode 100644 index 0000000..8086889 Binary files /dev/null and b/assets/images-webp/si/si_02_object.webp differ diff --git a/assets/images-webp/si/si_03_background.webp b/assets/images-webp/si/si_03_background.webp new file mode 100644 index 0000000..eb29ad2 Binary files /dev/null and b/assets/images-webp/si/si_03_background.webp differ diff --git a/assets/images-webp/si/si_03_object.webp b/assets/images-webp/si/si_03_object.webp new file mode 100644 index 0000000..70fa99c Binary files /dev/null and b/assets/images-webp/si/si_03_object.webp differ diff --git a/assets/images-webp/si/si_04_background.webp b/assets/images-webp/si/si_04_background.webp new file mode 100644 index 0000000..bd864fa Binary files /dev/null and b/assets/images-webp/si/si_04_background.webp differ diff --git a/assets/images-webp/si/si_04_object.webp b/assets/images-webp/si/si_04_object.webp new file mode 100644 index 0000000..f28bca0 Binary files /dev/null and b/assets/images-webp/si/si_04_object.webp differ diff --git a/assets/images-webp/si/si_05_background.webp b/assets/images-webp/si/si_05_background.webp new file mode 100644 index 0000000..26d76bb Binary files /dev/null and b/assets/images-webp/si/si_05_background.webp differ diff --git a/assets/images-webp/si/si_06_background.webp b/assets/images-webp/si/si_06_background.webp new file mode 100644 index 0000000..0268cec Binary files /dev/null and b/assets/images-webp/si/si_06_background.webp differ diff --git a/assets/images-webp/si/si_07_background.webp b/assets/images-webp/si/si_07_background.webp new file mode 100644 index 0000000..bcfcb6c Binary files /dev/null and b/assets/images-webp/si/si_07_background.webp differ diff --git a/assets/images-webp/si/si_07_object.webp b/assets/images-webp/si/si_07_object.webp new file mode 100644 index 0000000..54d0ae1 Binary files /dev/null and b/assets/images-webp/si/si_07_object.webp differ diff --git a/assets/images-webp/si/si_08_background.webp b/assets/images-webp/si/si_08_background.webp new file mode 100644 index 0000000..02ba0e8 Binary files /dev/null and b/assets/images-webp/si/si_08_background.webp differ diff --git a/assets/images-webp/si/si_08_object.webp b/assets/images-webp/si/si_08_object.webp new file mode 100644 index 0000000..8942995 Binary files /dev/null and b/assets/images-webp/si/si_08_object.webp differ diff --git a/assets/images-webp/solution/solution_01_background.webp b/assets/images-webp/solution/solution_01_background.webp new file mode 100644 index 0000000..bed3976 Binary files /dev/null and b/assets/images-webp/solution/solution_01_background.webp differ diff --git a/assets/images-webp/solution/solution_01_object.webp b/assets/images-webp/solution/solution_01_object.webp new file mode 100644 index 0000000..90042be Binary files /dev/null and b/assets/images-webp/solution/solution_01_object.webp differ diff --git a/assets/images-webp/solution/solution_02_background.webp b/assets/images-webp/solution/solution_02_background.webp new file mode 100644 index 0000000..4c282ba Binary files /dev/null and b/assets/images-webp/solution/solution_02_background.webp differ diff --git a/assets/images-webp/solution/solution_02_object.webp b/assets/images-webp/solution/solution_02_object.webp new file mode 100644 index 0000000..d820360 Binary files /dev/null and b/assets/images-webp/solution/solution_02_object.webp differ diff --git a/assets/images-webp/solution/solution_03_background.webp b/assets/images-webp/solution/solution_03_background.webp new file mode 100644 index 0000000..8be5de0 Binary files /dev/null and b/assets/images-webp/solution/solution_03_background.webp differ diff --git a/assets/images-webp/solution/solution_03_object.webp b/assets/images-webp/solution/solution_03_object.webp new file mode 100644 index 0000000..b0e2562 Binary files /dev/null and b/assets/images-webp/solution/solution_03_object.webp differ diff --git a/assets/images-webp/solution/solution_04_background.webp b/assets/images-webp/solution/solution_04_background.webp new file mode 100644 index 0000000..9a570e1 Binary files /dev/null and b/assets/images-webp/solution/solution_04_background.webp differ diff --git a/assets/images-webp/solution/solution_04_object.webp b/assets/images-webp/solution/solution_04_object.webp new file mode 100644 index 0000000..c9ca91c Binary files /dev/null and b/assets/images-webp/solution/solution_04_object.webp differ diff --git a/assets/images-webp/solution/solution_05_background.webp b/assets/images-webp/solution/solution_05_background.webp new file mode 100644 index 0000000..5af4bc7 Binary files /dev/null and b/assets/images-webp/solution/solution_05_background.webp differ diff --git a/assets/images-webp/solution/solution_05_object.webp b/assets/images-webp/solution/solution_05_object.webp new file mode 100644 index 0000000..213df06 Binary files /dev/null and b/assets/images-webp/solution/solution_05_object.webp differ diff --git a/assets/images-webp/solution/solution_06_background.webp b/assets/images-webp/solution/solution_06_background.webp new file mode 100644 index 0000000..59c6ac3 Binary files /dev/null and b/assets/images-webp/solution/solution_06_background.webp differ diff --git a/assets/images-webp/solution/solution_06_object.webp b/assets/images-webp/solution/solution_06_object.webp new file mode 100644 index 0000000..d0aed26 Binary files /dev/null and b/assets/images-webp/solution/solution_06_object.webp differ diff --git a/assets/images-webp/solution/solution_07_background.webp b/assets/images-webp/solution/solution_07_background.webp new file mode 100644 index 0000000..bf2d505 Binary files /dev/null and b/assets/images-webp/solution/solution_07_background.webp differ diff --git a/assets/images-webp/solution/solution_07_object.webp b/assets/images-webp/solution/solution_07_object.webp new file mode 100644 index 0000000..d3e004f Binary files /dev/null and b/assets/images-webp/solution/solution_07_object.webp differ diff --git a/assets/images-webp/solution/solution_08_background.webp b/assets/images-webp/solution/solution_08_background.webp new file mode 100644 index 0000000..79659ea Binary files /dev/null and b/assets/images-webp/solution/solution_08_background.webp differ diff --git a/assets/images-webp/solution/solution_08_object.webp b/assets/images-webp/solution/solution_08_object.webp new file mode 100644 index 0000000..4618f9b Binary files /dev/null and b/assets/images-webp/solution/solution_08_object.webp differ diff --git a/assets/images/automotive/automotive_01_background.jpeg b/assets/images/automotive/automotive_01_background.jpeg new file mode 100755 index 0000000..a55b8b2 --- /dev/null +++ b/assets/images/automotive/automotive_01_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14283a6e1e6dec897f84e44d742ee2dc1e2f3647600266044e3d3d635b027cb7 +size 1301208 diff --git a/assets/images/automotive/automotive_01_object.png b/assets/images/automotive/automotive_01_object.png new file mode 100755 index 0000000..7a7785c --- /dev/null +++ b/assets/images/automotive/automotive_01_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8097cde503b2cab4c4ef08d486fead2f8305fa7abe79e8c22d70e2954dec5c99 +size 1296504 diff --git a/assets/images/automotive/automotive_02_background.png b/assets/images/automotive/automotive_02_background.png new file mode 100755 index 0000000..945adf9 --- /dev/null +++ b/assets/images/automotive/automotive_02_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:96a2b146d63f800893b29195b64d310d4e022a23fe6cf197311541fbfa61bd14 +size 4280382 diff --git a/assets/images/automotive/automotive_02_object.png b/assets/images/automotive/automotive_02_object.png new file mode 100755 index 0000000..a15031a --- /dev/null +++ b/assets/images/automotive/automotive_02_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf679d96cdd5198e77b4afaa7d71c5d34bc6bd7d04848716fc7acd873400eed8 +size 1647854 diff --git a/assets/images/automotive/automotive_03_background.png b/assets/images/automotive/automotive_03_background.png new file mode 100755 index 0000000..4a74f4d --- /dev/null +++ b/assets/images/automotive/automotive_03_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d36b2d4c2ff3703b5ba2263fd1bdaa6a4efbc0d549d443ebb9d15880fbc5f89 +size 2235108 diff --git a/assets/images/automotive/automotive_03_object.png b/assets/images/automotive/automotive_03_object.png new file mode 100755 index 0000000..72a660f --- /dev/null +++ b/assets/images/automotive/automotive_03_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bcdd30f990249447859b4ce5f9ffbf3fa8fa54a041ce46b7d8985937f73e4973 +size 1678347 diff --git a/assets/images/automotive/automotive_04_background.jpeg b/assets/images/automotive/automotive_04_background.jpeg new file mode 100755 index 0000000..1e66b3b --- /dev/null +++ b/assets/images/automotive/automotive_04_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3609a27a410486b8606643c215d9fff71484b65d2adcc14253069a6e0b7f498b +size 1690753 diff --git a/assets/images/automotive/automotive_04_object.png b/assets/images/automotive/automotive_04_object.png new file mode 100755 index 0000000..a15031a --- /dev/null +++ b/assets/images/automotive/automotive_04_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf679d96cdd5198e77b4afaa7d71c5d34bc6bd7d04848716fc7acd873400eed8 +size 1647854 diff --git a/assets/images/automotive/automotive_05_background.png b/assets/images/automotive/automotive_05_background.png new file mode 100755 index 0000000..3e19edb --- /dev/null +++ b/assets/images/automotive/automotive_05_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:43ee2fcdbbcdb951450d15f36845027b8aed8d2d5d5045b1ed0866b42013ccdc +size 2188881 diff --git a/assets/images/automotive/automotive_05_object.png b/assets/images/automotive/automotive_05_object.png new file mode 100755 index 0000000..48efbbd --- /dev/null +++ b/assets/images/automotive/automotive_05_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1035c68c70f157b41f456e291069a621e3be42d7c9b3254512914e8179831eea +size 1715279 diff --git a/assets/images/automotive/automotive_06_background.png b/assets/images/automotive/automotive_06_background.png new file mode 100755 index 0000000..cee47d6 --- /dev/null +++ b/assets/images/automotive/automotive_06_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:304a33a8c94bea1fc3f81a1b6efef6eeb781824df680ab6d38be54e9d91dcc1a +size 2085654 diff --git a/assets/images/automotive/automotive_06_object.png b/assets/images/automotive/automotive_06_object.png new file mode 100755 index 0000000..7779954 --- /dev/null +++ b/assets/images/automotive/automotive_06_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1eec6773910207ce2f70052023d1794e89f02cff6d31351191857ffc044dfc38 +size 1687704 diff --git a/assets/images/automotive/automotive_07_background.jpeg b/assets/images/automotive/automotive_07_background.jpeg new file mode 100755 index 0000000..d1aecb7 --- /dev/null +++ b/assets/images/automotive/automotive_07_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f80d2c3b7e6afe062c6a6a427879c20345a7741ad3e959b9facefe33b081dc1 +size 2934876 diff --git a/assets/images/automotive/automotive_07_object.png b/assets/images/automotive/automotive_07_object.png new file mode 100755 index 0000000..da59efd --- /dev/null +++ b/assets/images/automotive/automotive_07_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ea150cf32747b09a9df16c08c99ee18d1a02e79aa3a6be169894c38c231f58c2 +size 1694976 diff --git a/assets/images/automotive/automotive_08_background.png b/assets/images/automotive/automotive_08_background.png new file mode 100755 index 0000000..b61d9ab --- /dev/null +++ b/assets/images/automotive/automotive_08_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f3e6768da44cec7d12f44747e83869930f493194c13d4eb831a293981dbd44e1 +size 2450833 diff --git a/assets/images/automotive/automotive_08_object.png b/assets/images/automotive/automotive_08_object.png new file mode 100644 index 0000000..b137782 --- /dev/null +++ b/assets/images/automotive/automotive_08_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e5eb8fd1a87a084fd649d6361c755f9b24bb62bb108417f9b3c0ac167da78152 +size 1274649 diff --git a/assets/images/automotive/automotive_08_object_origin.png b/assets/images/automotive/automotive_08_object_origin.png new file mode 100644 index 0000000..504344c --- /dev/null +++ b/assets/images/automotive/automotive_08_object_origin.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:016234443713e0b276fac3dcbbafc35228c3c3f93a0322e8d19c11e53b69ac78 +size 205514 diff --git a/assets/images/automotive/automotive_09_background.jpeg b/assets/images/automotive/automotive_09_background.jpeg new file mode 100755 index 0000000..0243fef --- /dev/null +++ b/assets/images/automotive/automotive_09_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1f36d9f22feb2482860c764f32fd7131d288beac2f7b048b597e728bac0df719 +size 1250635 diff --git a/assets/images/automotive/automotive_09_object-origin.png b/assets/images/automotive/automotive_09_object-origin.png new file mode 100644 index 0000000..81623e6 --- /dev/null +++ b/assets/images/automotive/automotive_09_object-origin.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f94e2509393133762d01b37c62a102f582d8850b1b84c77f1ad803793de25660 +size 436507 diff --git a/assets/images/automotive/automotive_09_object.png b/assets/images/automotive/automotive_09_object.png new file mode 100644 index 0000000..55be558 --- /dev/null +++ b/assets/images/automotive/automotive_09_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5b0a9c602c70c1ae41a10f0abeb3064fe6b28bc2d4b9b7566aa447a07c9a299b +size 1407773 diff --git a/assets/images/automotive/automotive_09_object_2.png b/assets/images/automotive/automotive_09_object_2.png new file mode 100644 index 0000000..72b2715 --- /dev/null +++ b/assets/images/automotive/automotive_09_object_2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a0a039afffb09c4a4abfca1400b692e30bb4264b367f933c07736d2c4f5baabb +size 1572695 diff --git a/assets/images/automotive/automotive_10_background.jpg b/assets/images/automotive/automotive_10_background.jpg new file mode 100755 index 0000000..2aef2c5 --- /dev/null +++ b/assets/images/automotive/automotive_10_background.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d0d2b2a69d1690e758956bbe642fd260508386639d52977909e66829fd7efda5 +size 2060835 diff --git a/assets/images/company-background.png b/assets/images/company-background.png new file mode 100755 index 0000000..e79af83 Binary files /dev/null and b/assets/images/company-background.png differ diff --git a/assets/images/esg/esg-management.png b/assets/images/esg/esg-management.png new file mode 100644 index 0000000..2492341 Binary files /dev/null and b/assets/images/esg/esg-management.png differ diff --git a/assets/images/esg/ethics-compliance.png b/assets/images/esg/ethics-compliance.png new file mode 100644 index 0000000..fdfbcee Binary files /dev/null and b/assets/images/esg/ethics-compliance.png differ diff --git a/assets/images/esg/safety-health.png b/assets/images/esg/safety-health.png new file mode 100644 index 0000000..a0508df Binary files /dev/null and b/assets/images/esg/safety-health.png differ diff --git a/assets/images/mobipin-logo.png b/assets/images/mobipin-logo.png new file mode 100755 index 0000000..1caa938 Binary files /dev/null and b/assets/images/mobipin-logo.png differ diff --git a/assets/images/partners/01_hyundai.png b/assets/images/partners/01_hyundai.png new file mode 100644 index 0000000..1ae74f2 Binary files /dev/null and b/assets/images/partners/01_hyundai.png differ diff --git a/assets/images/partners/02_hyundai_autoever.png b/assets/images/partners/02_hyundai_autoever.png new file mode 100644 index 0000000..944e0ee Binary files /dev/null and b/assets/images/partners/02_hyundai_autoever.png differ diff --git a/assets/images/partners/03_hyundai_wia.png b/assets/images/partners/03_hyundai_wia.png new file mode 100644 index 0000000..05f527f Binary files /dev/null and b/assets/images/partners/03_hyundai_wia.png differ diff --git a/assets/images/partners/04_sl_corporation.png b/assets/images/partners/04_sl_corporation.png new file mode 100644 index 0000000..6bbf13d Binary files /dev/null and b/assets/images/partners/04_sl_corporation.png differ diff --git a/assets/images/partners/05_kcar.png b/assets/images/partners/05_kcar.png new file mode 100644 index 0000000..3c584df Binary files /dev/null and b/assets/images/partners/05_kcar.png differ diff --git a/assets/images/partners/06_sk_securities.png b/assets/images/partners/06_sk_securities.png new file mode 100644 index 0000000..03cd555 Binary files /dev/null and b/assets/images/partners/06_sk_securities.png differ diff --git a/assets/images/partners/07_sk_networks.png b/assets/images/partners/07_sk_networks.png new file mode 100644 index 0000000..da14e86 Binary files /dev/null and b/assets/images/partners/07_sk_networks.png differ diff --git a/assets/images/partners/08_lg_electronics.png b/assets/images/partners/08_lg_electronics.png new file mode 100644 index 0000000..29ad88a Binary files /dev/null and b/assets/images/partners/08_lg_electronics.png differ diff --git a/assets/images/partners/09_hl_klemove.png b/assets/images/partners/09_hl_klemove.png new file mode 100644 index 0000000..69859f3 Binary files /dev/null and b/assets/images/partners/09_hl_klemove.png differ diff --git a/assets/images/partners/10_unitrontech.png b/assets/images/partners/10_unitrontech.png new file mode 100644 index 0000000..25e7137 Binary files /dev/null and b/assets/images/partners/10_unitrontech.png differ diff --git a/assets/images/partners/11_clobot.png b/assets/images/partners/11_clobot.png new file mode 100644 index 0000000..5043ff7 Binary files /dev/null and b/assets/images/partners/11_clobot.png differ diff --git a/assets/images/partners/12_kb_chachacah.png b/assets/images/partners/12_kb_chachacah.png new file mode 100644 index 0000000..5ea2a91 Binary files /dev/null and b/assets/images/partners/12_kb_chachacah.png differ diff --git a/assets/images/partners/13_wonderful_platform.png b/assets/images/partners/13_wonderful_platform.png new file mode 100644 index 0000000..7ed415e Binary files /dev/null and b/assets/images/partners/13_wonderful_platform.png differ diff --git a/assets/images/partners/14_ctr.png b/assets/images/partners/14_ctr.png new file mode 100644 index 0000000..5a143be Binary files /dev/null and b/assets/images/partners/14_ctr.png differ diff --git a/assets/images/patents/patents_01_object.jpg b/assets/images/patents/patents_01_object.jpg new file mode 100755 index 0000000..dfea8c9 --- /dev/null +++ b/assets/images/patents/patents_01_object.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0fb7895d78f1eb274465015bc889a3088c206c4df33b276bac3083896041a68d +size 309815 diff --git a/assets/images/patents/patents_01_object_02.jpg b/assets/images/patents/patents_01_object_02.jpg new file mode 100755 index 0000000..42867c7 --- /dev/null +++ b/assets/images/patents/patents_01_object_02.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c5d87997b7bd595f0e172435562f5d833043c560a4a3a1f883cab509c313fc86 +size 314668 diff --git a/assets/images/robotics-exhibition.png b/assets/images/robotics-exhibition.png new file mode 100755 index 0000000..bb36690 Binary files /dev/null and b/assets/images/robotics-exhibition.png differ diff --git a/assets/images/robotics/robotics_01_background.png b/assets/images/robotics/robotics_01_background.png new file mode 100644 index 0000000..16f10eb --- /dev/null +++ b/assets/images/robotics/robotics_01_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec6777dbef45896b4800053d91dcbe8fe3ae3a842a9f04351b0a0689039fc691 +size 1498731 diff --git a/assets/images/robotics/robotics_01_object.png b/assets/images/robotics/robotics_01_object.png new file mode 100644 index 0000000..88c87af --- /dev/null +++ b/assets/images/robotics/robotics_01_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2495e52cead43dedf702a7e9ac2558d35fd18027afe593f4f52aea9b1b1bf8cb +size 250883 diff --git a/assets/images/robotics/robotics_02_background.png b/assets/images/robotics/robotics_02_background.png new file mode 100755 index 0000000..aa7c52d --- /dev/null +++ b/assets/images/robotics/robotics_02_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4dbcb7a4f1cc4f4090118bc93725d81a34647d90d012820abb29664090679ce8 +size 1270296 diff --git a/assets/images/robotics/robotics_02_object.png b/assets/images/robotics/robotics_02_object.png new file mode 100644 index 0000000..19799df --- /dev/null +++ b/assets/images/robotics/robotics_02_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6adb11e08f181bfe7ed6ee4bd1d2c453b0830514751b6edd11a06458091f73b7 +size 7363251 diff --git a/assets/images/robotics/robotics_03_background.png b/assets/images/robotics/robotics_03_background.png new file mode 100644 index 0000000..567dc3a --- /dev/null +++ b/assets/images/robotics/robotics_03_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:397e6638acbe9d34e334742e6d63d8f6abac3da5f84ecae5d2fc7a9d6eb5275b +size 1450027 diff --git a/assets/images/robotics/robotics_03_object.png b/assets/images/robotics/robotics_03_object.png new file mode 100644 index 0000000..cf1d9ae --- /dev/null +++ b/assets/images/robotics/robotics_03_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b3cd23e4de87f634694b75cfa71d0f2def4c4b32d25020e85c5a8e8228a0c0e +size 1348774 diff --git a/assets/images/robotics/robotics_04_background.png b/assets/images/robotics/robotics_04_background.png new file mode 100644 index 0000000..d5b41d3 --- /dev/null +++ b/assets/images/robotics/robotics_04_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4f8a901f071292d61597870b1015b3cf66d3c9e06de53c50a471f45377b31ed +size 1477275 diff --git a/assets/images/robotics/robotics_04_object.png b/assets/images/robotics/robotics_04_object.png new file mode 100644 index 0000000..f8f6f34 --- /dev/null +++ b/assets/images/robotics/robotics_04_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:62f6f752d32902df69c719c5fa748f74a6c6f44ba32645aea8ff671182321b53 +size 1109558 diff --git a/assets/images/si/si_01_background.jpeg b/assets/images/si/si_01_background.jpeg new file mode 100755 index 0000000..12a45d7 --- /dev/null +++ b/assets/images/si/si_01_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d1ed82f125b032f8f1408245485205c5b334dfe9ff42cb7a91a28bdaa75951c +size 2695576 diff --git a/assets/images/si/si_01_object.png b/assets/images/si/si_01_object.png new file mode 100644 index 0000000..0c68acf --- /dev/null +++ b/assets/images/si/si_01_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e192bfba6a3a661582bb4dfd52fc843fabfbc3cce7f0dcd6bd9156a6fe79b82c +size 253470 diff --git a/assets/images/si/si_02_background.jpg b/assets/images/si/si_02_background.jpg new file mode 100755 index 0000000..b4a668b --- /dev/null +++ b/assets/images/si/si_02_background.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e19a4faac9d0b90c6423acb05cf208fdb7d302d2a1123a6d044009bd8f69f457 +size 6456575 diff --git a/assets/images/si/si_02_object.png b/assets/images/si/si_02_object.png new file mode 100644 index 0000000..e3d1801 --- /dev/null +++ b/assets/images/si/si_02_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d7455323e1a58fcde5c8704d75044262f305def4dd8673672869355f2cd53ff0 +size 432235 diff --git a/assets/images/si/si_03_background.png b/assets/images/si/si_03_background.png new file mode 100755 index 0000000..e9f4f4f --- /dev/null +++ b/assets/images/si/si_03_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:865d6dd6ccb12d59b0ccc2225bc66eb9c5cc9e2b0c23251744f0416e3476a082 +size 2289210 diff --git a/assets/images/si/si_03_object.png b/assets/images/si/si_03_object.png new file mode 100644 index 0000000..1d2f223 --- /dev/null +++ b/assets/images/si/si_03_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c262c7979206c361dc30d09158281913cb4874e7c8bcf251c7cdf3bdace10e22 +size 868126 diff --git a/assets/images/si/si_04_background.png b/assets/images/si/si_04_background.png new file mode 100755 index 0000000..9ce0b23 --- /dev/null +++ b/assets/images/si/si_04_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3bd4437d9286381a714f810739dc061d555ee315b2e3fac7e245aa3654560197 +size 2248056 diff --git a/assets/images/si/si_04_object.png b/assets/images/si/si_04_object.png new file mode 100644 index 0000000..93a939c --- /dev/null +++ b/assets/images/si/si_04_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a5c730ab91bc70b1bdc0845e27e449885107b9598e657b673bb094a44d29308e +size 663715 diff --git a/assets/images/si/si_05_background.png b/assets/images/si/si_05_background.png new file mode 100755 index 0000000..4f9f8a3 --- /dev/null +++ b/assets/images/si/si_05_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:063cc84f7cd1cb8d273bf3e70a233fea7fb82fd39191a5b96c1a3a623b7f7806 +size 1375425 diff --git a/assets/images/si/si_06_background.png b/assets/images/si/si_06_background.png new file mode 100755 index 0000000..c185558 --- /dev/null +++ b/assets/images/si/si_06_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:febc9694934a192c56ae86d48ea1e077db1870766254847954253a6a8a6c5cca +size 1746954 diff --git a/assets/images/si/si_07_background.png b/assets/images/si/si_07_background.png new file mode 100755 index 0000000..51d19bd --- /dev/null +++ b/assets/images/si/si_07_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9d3cd2950f6b8484403173d4ea56e6e08b4094db80f102c6f6a2baa67a880b1e +size 2166516 diff --git a/assets/images/si/si_07_object.png b/assets/images/si/si_07_object.png new file mode 100644 index 0000000..3342e56 --- /dev/null +++ b/assets/images/si/si_07_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f0f7f7edd5b4207db421bc253886f95b0372a87dc8a4ab4d1d93b3e24da6463d +size 1185671 diff --git a/assets/images/si/si_08_background.png b/assets/images/si/si_08_background.png new file mode 100755 index 0000000..3a4cb76 --- /dev/null +++ b/assets/images/si/si_08_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:14cc2e6becd9b272513887484730066e00733886412ad50366c5902789e97486 +size 239647 diff --git a/assets/images/si/si_08_object.png b/assets/images/si/si_08_object.png new file mode 100644 index 0000000..3279f42 --- /dev/null +++ b/assets/images/si/si_08_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:12b5e400a70dac30cb40c5c85cb60add1ec404555c06cba5ed57f42558e41e20 +size 958638 diff --git a/assets/images/solution/solution_01_background.jpeg b/assets/images/solution/solution_01_background.jpeg new file mode 100755 index 0000000..a644934 --- /dev/null +++ b/assets/images/solution/solution_01_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd7a3a1ce94b548374c541d4e223a0a1e99cf1b92a49201f97c6753f402a978f +size 2678832 diff --git a/assets/images/solution/solution_01_object.png b/assets/images/solution/solution_01_object.png new file mode 100644 index 0000000..2a032bb --- /dev/null +++ b/assets/images/solution/solution_01_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a77db29770be4ac5e2e0d01f92f57079a917906592ba124b417fb3485ff0b1f4 +size 1496174 diff --git a/assets/images/solution/solution_02_background.png b/assets/images/solution/solution_02_background.png new file mode 100755 index 0000000..23ef393 --- /dev/null +++ b/assets/images/solution/solution_02_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ecd4099386db2adc53a1b84af72a5d974f55ee2854bfb6a80e61280c84b5e033 +size 2435496 diff --git a/assets/images/solution/solution_02_object.png b/assets/images/solution/solution_02_object.png new file mode 100644 index 0000000..856cdfb --- /dev/null +++ b/assets/images/solution/solution_02_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c8f48e69b05eebd7d8ff5ccdda9b9005d0b514afbebc960d685f5b2f8a313b4e +size 1587328 diff --git a/assets/images/solution/solution_02_object_origin.png b/assets/images/solution/solution_02_object_origin.png new file mode 100644 index 0000000..446147f --- /dev/null +++ b/assets/images/solution/solution_02_object_origin.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5f471a2f981dc5666d4881e7ce41ee44014acc277023a6fb92223ee39b5d8a8e +size 2126451 diff --git a/assets/images/solution/solution_03_background.png b/assets/images/solution/solution_03_background.png new file mode 100644 index 0000000..9bb88c9 --- /dev/null +++ b/assets/images/solution/solution_03_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ab6213f8622fed7f9a58580f2f333efbcaf78665d7ac8ba94ea24217f6412ca +size 1800692 diff --git a/assets/images/solution/solution_03_background_origin.png b/assets/images/solution/solution_03_background_origin.png new file mode 100755 index 0000000..7cf1e2f --- /dev/null +++ b/assets/images/solution/solution_03_background_origin.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:975fed861ec97b2b6a4bbeed050183c5918db54b7e850653559a44ac0e7c0fe0 +size 2479449 diff --git a/assets/images/solution/solution_03_object.png b/assets/images/solution/solution_03_object.png new file mode 100644 index 0000000..07a4f93 --- /dev/null +++ b/assets/images/solution/solution_03_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:47f59a24cf3ee0ae81dd890fd3be87a975903eb6d3077cc3cc41d753c962c3b1 +size 1342894 diff --git a/assets/images/solution/solution_03_object_origin.png b/assets/images/solution/solution_03_object_origin.png new file mode 100644 index 0000000..c402f52 --- /dev/null +++ b/assets/images/solution/solution_03_object_origin.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cee80f0a028e7835e429cd68694a27e774a994962fddb5a44756cdbd56c5842e +size 777430 diff --git a/assets/images/solution/solution_04_background.png b/assets/images/solution/solution_04_background.png new file mode 100755 index 0000000..d6e80a2 --- /dev/null +++ b/assets/images/solution/solution_04_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d835ecd89d6e3722f182b24a79a480c1c76c0d7b532eed95cae355d868ca833b +size 2843194 diff --git a/assets/images/solution/solution_04_object.png b/assets/images/solution/solution_04_object.png new file mode 100644 index 0000000..89f3f5b --- /dev/null +++ b/assets/images/solution/solution_04_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c66723278419cb2c7ba3e4a63a29e00d93ce32d03c2b2986d958da212135ae7 +size 268350 diff --git a/assets/images/solution/solution_05_background.png b/assets/images/solution/solution_05_background.png new file mode 100755 index 0000000..9750d86 --- /dev/null +++ b/assets/images/solution/solution_05_background.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b829e5cf61de0f19f00de7a0c4a1f88b04d18e5aad2f8121fbc95fc35b4f2b1 +size 2190771 diff --git a/assets/images/solution/solution_05_object.png b/assets/images/solution/solution_05_object.png new file mode 100644 index 0000000..252484b --- /dev/null +++ b/assets/images/solution/solution_05_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:33124fe58f4eeb7514944d5d9db8a241b34ca9bbc1db77d09e70c88fba6fe770 +size 910126 diff --git a/assets/images/solution/solution_06_background.jpeg b/assets/images/solution/solution_06_background.jpeg new file mode 100755 index 0000000..c5fa15d --- /dev/null +++ b/assets/images/solution/solution_06_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b934eee983f45a5da007bea588331a8b3867ab2bec0968b42981110ce6f7e6ce +size 1696232 diff --git a/assets/images/solution/solution_06_object.png b/assets/images/solution/solution_06_object.png new file mode 100644 index 0000000..61d43c8 --- /dev/null +++ b/assets/images/solution/solution_06_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a8f13535a072f4f27ff33e7f01734b0e21716974f7780d56b68f35aa920b0af9 +size 651558 diff --git a/assets/images/solution/solution_07_background.jpeg b/assets/images/solution/solution_07_background.jpeg new file mode 100755 index 0000000..6d753a6 --- /dev/null +++ b/assets/images/solution/solution_07_background.jpeg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f64eab6ec8a6301ae897ed9045cc5aeb90cd238beadfb60c0ac805e95ceffff9 +size 1929703 diff --git a/assets/images/solution/solution_07_object.png b/assets/images/solution/solution_07_object.png new file mode 100644 index 0000000..dca8384 --- /dev/null +++ b/assets/images/solution/solution_07_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5d33592326658e1d0ed5ce5200dba68765482c82f3689689488de13a1e577cf1 +size 753033 diff --git a/assets/images/solution/solution_08_background.jpg b/assets/images/solution/solution_08_background.jpg new file mode 100755 index 0000000..99833e3 --- /dev/null +++ b/assets/images/solution/solution_08_background.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dfedcc58873a70f7930caf22de561f6877f3a3f31b2a629d48768becdebae7a5 +size 316727 diff --git a/assets/images/solution/solution_08_object.png b/assets/images/solution/solution_08_object.png new file mode 100644 index 0000000..8708521 --- /dev/null +++ b/assets/images/solution/solution_08_object.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bf84146daca41d867f4547c41076fab2ee78db73419c6bf78f26bd2e423f69c4 +size 960467 diff --git a/assets/images/vehicle-3d-solution.png b/assets/images/vehicle-3d-solution.png new file mode 100755 index 0000000..4862539 Binary files /dev/null and b/assets/images/vehicle-3d-solution.png differ diff --git a/assets/partner-placeholder.svg b/assets/partner-placeholder.svg new file mode 100644 index 0000000..c02c112 --- /dev/null +++ b/assets/partner-placeholder.svg @@ -0,0 +1,6 @@ + + + + + LOGO + diff --git a/assets/thumbnails/automotive/automotive_01_background.jpeg b/assets/thumbnails/automotive/automotive_01_background.jpeg new file mode 100644 index 0000000..6c1e6c7 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_01_background.jpeg differ diff --git a/assets/thumbnails/automotive/automotive_01_object.png b/assets/thumbnails/automotive/automotive_01_object.png new file mode 100644 index 0000000..7f28047 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_01_object.png differ diff --git a/assets/thumbnails/automotive/automotive_02_background.png b/assets/thumbnails/automotive/automotive_02_background.png new file mode 100644 index 0000000..a585036 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_02_background.png differ diff --git a/assets/thumbnails/automotive/automotive_02_object.png b/assets/thumbnails/automotive/automotive_02_object.png new file mode 100644 index 0000000..70186a9 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_02_object.png differ diff --git a/assets/thumbnails/automotive/automotive_03_background.png b/assets/thumbnails/automotive/automotive_03_background.png new file mode 100644 index 0000000..c6388a4 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_03_background.png differ diff --git a/assets/thumbnails/automotive/automotive_03_object.png b/assets/thumbnails/automotive/automotive_03_object.png new file mode 100644 index 0000000..95c0a2a Binary files /dev/null and b/assets/thumbnails/automotive/automotive_03_object.png differ diff --git a/assets/thumbnails/automotive/automotive_04_background.jpeg b/assets/thumbnails/automotive/automotive_04_background.jpeg new file mode 100644 index 0000000..3e51109 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_04_background.jpeg differ diff --git a/assets/thumbnails/automotive/automotive_04_object.png b/assets/thumbnails/automotive/automotive_04_object.png new file mode 100644 index 0000000..70186a9 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_04_object.png differ diff --git a/assets/thumbnails/automotive/automotive_05_background.png b/assets/thumbnails/automotive/automotive_05_background.png new file mode 100644 index 0000000..8f780a2 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_05_background.png differ diff --git a/assets/thumbnails/automotive/automotive_05_object.png b/assets/thumbnails/automotive/automotive_05_object.png new file mode 100644 index 0000000..3612e69 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_05_object.png differ diff --git a/assets/thumbnails/automotive/automotive_06_background.png b/assets/thumbnails/automotive/automotive_06_background.png new file mode 100644 index 0000000..eaecc50 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_06_background.png differ diff --git a/assets/thumbnails/automotive/automotive_06_object.png b/assets/thumbnails/automotive/automotive_06_object.png new file mode 100644 index 0000000..97f3f48 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_06_object.png differ diff --git a/assets/thumbnails/automotive/automotive_07_background.jpeg b/assets/thumbnails/automotive/automotive_07_background.jpeg new file mode 100644 index 0000000..4150d14 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_07_background.jpeg differ diff --git a/assets/thumbnails/automotive/automotive_07_object.png b/assets/thumbnails/automotive/automotive_07_object.png new file mode 100644 index 0000000..54d8823 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_07_object.png differ diff --git a/assets/thumbnails/automotive/automotive_08_background.png b/assets/thumbnails/automotive/automotive_08_background.png new file mode 100644 index 0000000..c5c6cf7 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_08_background.png differ diff --git a/assets/thumbnails/automotive/automotive_08_object.png b/assets/thumbnails/automotive/automotive_08_object.png new file mode 100644 index 0000000..ecc7185 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_08_object.png differ diff --git a/assets/thumbnails/automotive/automotive_09_background.jpeg b/assets/thumbnails/automotive/automotive_09_background.jpeg new file mode 100644 index 0000000..4fce50d Binary files /dev/null and b/assets/thumbnails/automotive/automotive_09_background.jpeg differ diff --git a/assets/thumbnails/automotive/automotive_09_object.png b/assets/thumbnails/automotive/automotive_09_object.png new file mode 100644 index 0000000..c879865 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_09_object.png differ diff --git a/assets/thumbnails/automotive/automotive_10_background.jpg b/assets/thumbnails/automotive/automotive_10_background.jpg new file mode 100644 index 0000000..fe52f33 Binary files /dev/null and b/assets/thumbnails/automotive/automotive_10_background.jpg differ diff --git a/assets/thumbnails/patents/patents_01_object.jpg b/assets/thumbnails/patents/patents_01_object.jpg new file mode 100644 index 0000000..eef30eb Binary files /dev/null and b/assets/thumbnails/patents/patents_01_object.jpg differ diff --git a/assets/thumbnails/patents/patents_01_object_02.jpg b/assets/thumbnails/patents/patents_01_object_02.jpg new file mode 100644 index 0000000..b789fb9 Binary files /dev/null and b/assets/thumbnails/patents/patents_01_object_02.jpg differ diff --git a/assets/thumbnails/robotics/robotics_01_background.png b/assets/thumbnails/robotics/robotics_01_background.png new file mode 100644 index 0000000..6f78bf1 Binary files /dev/null and b/assets/thumbnails/robotics/robotics_01_background.png differ diff --git a/assets/thumbnails/robotics/robotics_01_object.png b/assets/thumbnails/robotics/robotics_01_object.png new file mode 100644 index 0000000..3ec96b1 Binary files /dev/null and b/assets/thumbnails/robotics/robotics_01_object.png differ diff --git a/assets/thumbnails/robotics/robotics_02_background.png b/assets/thumbnails/robotics/robotics_02_background.png new file mode 100644 index 0000000..8b2ff4c Binary files /dev/null and b/assets/thumbnails/robotics/robotics_02_background.png differ diff --git a/assets/thumbnails/robotics/robotics_02_object.png b/assets/thumbnails/robotics/robotics_02_object.png new file mode 100644 index 0000000..c72237d Binary files /dev/null and b/assets/thumbnails/robotics/robotics_02_object.png differ diff --git a/assets/thumbnails/robotics/robotics_03_background.png b/assets/thumbnails/robotics/robotics_03_background.png new file mode 100644 index 0000000..ab96859 Binary files /dev/null and b/assets/thumbnails/robotics/robotics_03_background.png differ diff --git a/assets/thumbnails/robotics/robotics_03_object.png b/assets/thumbnails/robotics/robotics_03_object.png new file mode 100644 index 0000000..164b363 Binary files /dev/null and b/assets/thumbnails/robotics/robotics_03_object.png differ diff --git a/assets/thumbnails/robotics/robotics_04_background.png b/assets/thumbnails/robotics/robotics_04_background.png new file mode 100644 index 0000000..773191f Binary files /dev/null and b/assets/thumbnails/robotics/robotics_04_background.png differ diff --git a/assets/thumbnails/robotics/robotics_04_object.png b/assets/thumbnails/robotics/robotics_04_object.png new file mode 100644 index 0000000..3e90349 Binary files /dev/null and b/assets/thumbnails/robotics/robotics_04_object.png differ diff --git a/assets/thumbnails/si/si_01_background.jpeg b/assets/thumbnails/si/si_01_background.jpeg new file mode 100644 index 0000000..8089338 Binary files /dev/null and b/assets/thumbnails/si/si_01_background.jpeg differ diff --git a/assets/thumbnails/si/si_01_object.png b/assets/thumbnails/si/si_01_object.png new file mode 100644 index 0000000..4135981 Binary files /dev/null and b/assets/thumbnails/si/si_01_object.png differ diff --git a/assets/thumbnails/si/si_02_background.jpg b/assets/thumbnails/si/si_02_background.jpg new file mode 100644 index 0000000..137a2dc Binary files /dev/null and b/assets/thumbnails/si/si_02_background.jpg differ diff --git a/assets/thumbnails/si/si_02_object.png b/assets/thumbnails/si/si_02_object.png new file mode 100644 index 0000000..218dd06 Binary files /dev/null and b/assets/thumbnails/si/si_02_object.png differ diff --git a/assets/thumbnails/si/si_03_background.png b/assets/thumbnails/si/si_03_background.png new file mode 100644 index 0000000..8f688b2 Binary files /dev/null and b/assets/thumbnails/si/si_03_background.png differ diff --git a/assets/thumbnails/si/si_03_object.png b/assets/thumbnails/si/si_03_object.png new file mode 100644 index 0000000..7978074 Binary files /dev/null and b/assets/thumbnails/si/si_03_object.png differ diff --git a/assets/thumbnails/si/si_04_background.png b/assets/thumbnails/si/si_04_background.png new file mode 100644 index 0000000..7a0a452 Binary files /dev/null and b/assets/thumbnails/si/si_04_background.png differ diff --git a/assets/thumbnails/si/si_04_object.png b/assets/thumbnails/si/si_04_object.png new file mode 100644 index 0000000..99037bc Binary files /dev/null and b/assets/thumbnails/si/si_04_object.png differ diff --git a/assets/thumbnails/si/si_05_background.png b/assets/thumbnails/si/si_05_background.png new file mode 100644 index 0000000..0c1441c Binary files /dev/null and b/assets/thumbnails/si/si_05_background.png differ diff --git a/assets/thumbnails/si/si_06_background.png b/assets/thumbnails/si/si_06_background.png new file mode 100644 index 0000000..3168dbd Binary files /dev/null and b/assets/thumbnails/si/si_06_background.png differ diff --git a/assets/thumbnails/si/si_07_background.png b/assets/thumbnails/si/si_07_background.png new file mode 100644 index 0000000..6daf430 Binary files /dev/null and b/assets/thumbnails/si/si_07_background.png differ diff --git a/assets/thumbnails/si/si_07_object.png b/assets/thumbnails/si/si_07_object.png new file mode 100644 index 0000000..d3a6e69 Binary files /dev/null and b/assets/thumbnails/si/si_07_object.png differ diff --git a/assets/thumbnails/si/si_08_background.png b/assets/thumbnails/si/si_08_background.png new file mode 100644 index 0000000..e9fcb66 Binary files /dev/null and b/assets/thumbnails/si/si_08_background.png differ diff --git a/assets/thumbnails/si/si_08_object.png b/assets/thumbnails/si/si_08_object.png new file mode 100644 index 0000000..cad767d Binary files /dev/null and b/assets/thumbnails/si/si_08_object.png differ diff --git a/assets/thumbnails/solution/solution_01_background.jpeg b/assets/thumbnails/solution/solution_01_background.jpeg new file mode 100644 index 0000000..714d46d Binary files /dev/null and b/assets/thumbnails/solution/solution_01_background.jpeg differ diff --git a/assets/thumbnails/solution/solution_01_object.png b/assets/thumbnails/solution/solution_01_object.png new file mode 100644 index 0000000..a1a89fc Binary files /dev/null and b/assets/thumbnails/solution/solution_01_object.png differ diff --git a/assets/thumbnails/solution/solution_02_background.png b/assets/thumbnails/solution/solution_02_background.png new file mode 100644 index 0000000..f691832 Binary files /dev/null and b/assets/thumbnails/solution/solution_02_background.png differ diff --git a/assets/thumbnails/solution/solution_02_object.png b/assets/thumbnails/solution/solution_02_object.png new file mode 100644 index 0000000..8396fa2 Binary files /dev/null and b/assets/thumbnails/solution/solution_02_object.png differ diff --git a/assets/thumbnails/solution/solution_03_background.png b/assets/thumbnails/solution/solution_03_background.png new file mode 100644 index 0000000..15a086e Binary files /dev/null and b/assets/thumbnails/solution/solution_03_background.png differ diff --git a/assets/thumbnails/solution/solution_03_object.png b/assets/thumbnails/solution/solution_03_object.png new file mode 100644 index 0000000..f48391a Binary files /dev/null and b/assets/thumbnails/solution/solution_03_object.png differ diff --git a/assets/thumbnails/solution/solution_04_background.png b/assets/thumbnails/solution/solution_04_background.png new file mode 100644 index 0000000..ebd9c83 Binary files /dev/null and b/assets/thumbnails/solution/solution_04_background.png differ diff --git a/assets/thumbnails/solution/solution_04_object.png b/assets/thumbnails/solution/solution_04_object.png new file mode 100644 index 0000000..b45795a Binary files /dev/null and b/assets/thumbnails/solution/solution_04_object.png differ diff --git a/assets/thumbnails/solution/solution_05_background.png b/assets/thumbnails/solution/solution_05_background.png new file mode 100644 index 0000000..ae61431 Binary files /dev/null and b/assets/thumbnails/solution/solution_05_background.png differ diff --git a/assets/thumbnails/solution/solution_05_object.png b/assets/thumbnails/solution/solution_05_object.png new file mode 100644 index 0000000..2a2e746 Binary files /dev/null and b/assets/thumbnails/solution/solution_05_object.png differ diff --git a/assets/thumbnails/solution/solution_06_background.jpeg b/assets/thumbnails/solution/solution_06_background.jpeg new file mode 100644 index 0000000..cb6ec0b Binary files /dev/null and b/assets/thumbnails/solution/solution_06_background.jpeg differ diff --git a/assets/thumbnails/solution/solution_06_object.png b/assets/thumbnails/solution/solution_06_object.png new file mode 100644 index 0000000..8e8177d Binary files /dev/null and b/assets/thumbnails/solution/solution_06_object.png differ diff --git a/assets/thumbnails/solution/solution_07_background.jpeg b/assets/thumbnails/solution/solution_07_background.jpeg new file mode 100644 index 0000000..365a9fa Binary files /dev/null and b/assets/thumbnails/solution/solution_07_background.jpeg differ diff --git a/assets/thumbnails/solution/solution_07_object.png b/assets/thumbnails/solution/solution_07_object.png new file mode 100644 index 0000000..b402e10 Binary files /dev/null and b/assets/thumbnails/solution/solution_07_object.png differ diff --git a/assets/thumbnails/solution/solution_08_background.jpg b/assets/thumbnails/solution/solution_08_background.jpg new file mode 100644 index 0000000..190a5b6 Binary files /dev/null and b/assets/thumbnails/solution/solution_08_background.jpg differ diff --git a/assets/thumbnails/solution/solution_08_object.png b/assets/thumbnails/solution/solution_08_object.png new file mode 100644 index 0000000..4c80a2f Binary files /dev/null and b/assets/thumbnails/solution/solution_08_object.png differ diff --git a/capabilities.html b/capabilities.html new file mode 100644 index 0000000..805d7ce --- /dev/null +++ b/capabilities.html @@ -0,0 +1,334 @@ + + + + + + + Technical Capabilities · MOBIPINTECH + + + + + + + + + + + + +
+
+
+
+ + +
+

Automotive

+

전장 기술 역량

+

+ Automotive Software Technical Capabilities +

+

+ 차량의 제어, 통신, 인포테인먼트, 검증 자동화까지 실제 개발 범위에 + 가까운 사례를 모았습니다. +

+
+ +
+ + + + + + +
+
+ +
+ + +
+
+ +
+
+ + +
+

모비핀테크놀러지 기술 역량

+

+ 모비핀테크놀러지는 자동차 전장, 로봇, 솔루션, SI 영역에서 실제 운영 환경에 적용되는 소프트웨어를 개발합니다. +

+
+

Automotive 전장 기술 역량

+
+

SBCM SW 개발

+

1·2세대 총 32개 차종에 적용되는 SBCM(Seat/Body Control Module) 소프트웨어를 개발하고, OMU, AFCU, CDM, E-LATCH, PDL, PDS, RDC, EHL 등 주요 차량 바디 제어 기능을 차종별 요구사항에 맞게 구현하였습니다. Mobilgene AUTOSAR 기반 환경에서 SWC(Software Component)를 구성하고 소프트웨어를 Build하여 차량 제어 시스템에 적용할 수 있는 개발 환경을 구축하였으며, 다양한 차종과 세대별 사양에 대응할 수 있도록 기능을 체계적으로 개발하였습니다. MATLAB Simulink를 활용한 Model 기반 Application Software 설계 및 검증을 수행하여 기능 요구사항을 모델로 구현하고 소프트웨어 동작을 검증하였습니다. 또한 Sleep/Wake-up, 진단 기능, HSM 보안 모듈, Fail-Safe 등 비기능 요구사항을 함께 개발하고 검증하였습니다. 정적 및 동적 검증을 수행하고, QAC, CodeSonar, HKSAT, FossID 등 다양한 검증 Tool을 활용하여 소스 코드의 품질과 잠재적인 결함, 보안 취약 요소 등을 검증하였습니다. ISO 26262 기능 안전 개발 프로세스 기반 업무 (ASIL, FMEA, DFA) 를 수행하였습니다.

+
+
+

차량용 공조제어기 SW 개발

+

H-VAC Controller Application Software

+

기존 Non-AUTOSAR 기반으로 개발된 차량용 공조제어기 소프트웨어를 AUTOSAR 기반의 표준화된 구조로 전환하고, 소프트웨어 아키텍처 설계부터 기능 구현 및 검증까지 수행하였습니다. 기존 소프트웨어의 기능과 구조를 분석하여 AUTOSAR 환경에 적합하도록 ASW(Application Software) 영역의 아키텍처를 새롭게 설계하고, 제어기 소프트웨어의 구성 요소를 체계적으로 재구성하였습니다. AUTOSAR ASW 구조에 따라 SWC(Software Component)를 생성하고 각 Component에 필요한 PORT와 Interface를 정의하였으며, Event 및 Runnable을 구성하여 소프트웨어 기능 간의 관계와 실행 구조를 설계하였습니다. RTE( Runtime Environment)를 Generate하고 BSW 영역과 연계하여 Application Software와 하위 소프트웨어 계층 간의 정상적인 기능 호출 및 데이터 통신이 가능하도록 통합 작업을 수행하였습니다. 전환 과정에서 발생하는 기능 결함과 연계 오류에 대한 대응 업무를 수행하고, SW Test를 통해 각 기능의 정상 동작 여부를 검증하였습니다. Non-AUTOSAR 기반의 기존 공조제어기 소프트웨어를 AUTOSAR 표준 구조로 성공적으로 전환하고, ASW 아키텍처 설계부터 SWC 구성, RTE Generate 및 BSW 연계, SW Test와 결함 분석·Debugging까지 전반적인 AUTOSAR 전환 및 검증 업무를 수행하였습니다.

+
+
+

Autonomous Vehicle FCM 제어기 개발

+

Front Camera Module Controller

+

자율주행 차량의 핵심 전장 기능을 안정적으로 지원할 수 있도록 AUTOSAR 기반 FCM 제어기의 소프트웨어 아키텍처 설계 및 핵심 모듈 통합 개발을 수행하였습니다. AUTOSAR BSW 아키텍처를 기반으로 제어기 소프트웨어 구조를 설계하고 주요 BSW 모듈을 통합하여 차량 전장 환경에 적합한 소프트웨어 플랫폼을 구성하였습니다. 차량 진단 기능을 위한 Application을 개발하고 Cyber Security 관련 사양과 연계하여 ASK 등의 보안 기능을 적용하였으며, CAN 및 CAN-FD 기반 차량 통신 기능을 구현하여 차량 네트워크와의 안정적인 데이터 연계가 가능하도록 구성하였습니다. 또한 DCM을 비롯한 일부 하위 CAN 및 Ethernet AUTOSAR Layer Stack을 개발하였습니다. ISO 및 OEM 요구사항을 기반으로 DoCAN 및 DoIP Stack을 개발하여 CAN 및 Ethernet 환경에서의 진단 통신 기능을 구현하였으며, Bootloader 진단 사양과 Reprogramming 기능을 개발하여 제어기의 안정적인 소프트웨어 업데이트 환경을 구축하였습니다. 이와 함께 Application 영역의 진단 사양을 개발하여 제어기 내부 기능과 진단 시스템 간의 연계성을 확보하였습니다. 이를 통해 AUTOSAR 기반 BSW 아키텍처 설계 및 모듈 통합부터 차량 통신, 진단 Application, Cyber Security, Bootloader 및 DoCAN·DoIP 통신 Stack까지 FCM 제어기 개발에 필요한 핵심 소프트웨어 영역을 종합적으로 구현하였습니다.

+
+
+

차량용 공조제어기 SW 개발

+

H-VAC Controller Basic Software

+

차량용 공조제어기의 안정적인 소프트웨어 동작과 차량 전장 시스템과의 원활한 연계를 위해 AUTOSAR 기반의 BSW 및 Middleware를 개발하고, 제어기의 핵심 기능과 진단·보안·업데이트 기능을 통합 구현하였습니다. FBL(Flash Boot Loader) 기능을 구현하고 Sleep & Wake-up 사양을 개발하여 차량의 전원 상태 변화에 따른 제어기의 안정적인 동작 환경을 확보하였습니다. BSW Configuration 및 Implementation을 수행하고 Middleware를 구현하였으며, M-CAL Port를 비롯하여 ADC, PWM, ICU, IoHwAb, OS 등 주요 AUTOSAR 모듈을 설정하고 제어기 사양에 맞게 통합하였습니다. 또한 CAN 요구사항을 반영하여 관련 DB를 Import하고 Generate 및 Harmonize 과정을 수행함으로써 차량 네트워크 환경과 제어기 소프트웨어 간의 통신 연계성을 구현하였습니다. 보안 기능 강화를 위해 HSM, ASK, SFM 및 Crypto Library를 포팅하고 기능 검증을 수행하여 차량용 제어기에 요구되는 보안 기능을 안정적으로 적용하였습니다. 진단 영역에서는 DiagDCM 및 DEM Configuration을 수행하고 관련 기능을 검증하여 차량 진단 시스템과 제어기 간의 안정적인 진단 환경을 구축하였습니다. OTA(Over-The-Air) 기반 Background 및 Reprogramming 기능을 개발하고 검증하여 차량 소프트웨어를 안정적으로 업데이트할 수 있는 환경을 구현하였습니다. Watch-Dog 요구사항을 반영 개발하였습니다.

+
+
+

A-SPICE 기반 SWE5 통합검증

+

Software Engineering Process Integration Test

+

자동차 소프트웨어 개발 프로세스의 품질과 신뢰성을 확보하기 위해 A-SPICE 기반 SWE5 Software Integration Test 환경을 구축하고 소프트웨어 통합검증을 수행하였습니다. 요구사항 및 소프트웨어 설계 분석을 기반으로 테스트 범위를 정의하고,검증 목적에 적합한 Test Case를 개발하여 소프트웨어 구성 요소 간 통합 동작과 기능을 체계적으로 검증하였습니다. HKMC ES 95490-10 기준에 따라 소프트웨어 통합검증을 수행하고, 테스트 결과에 대한 Coverage를 분석하여 검증 범위와 결과를 정량적으로 관리할 수 있도록 하였습니다. 테스트 과정에서 발생한 이상 동작 및 이슈에 대해서는 원인을 분석하고 결과를 체계적으로 관리하였으며, 검증 결과와 이슈 분석 내용을 기반으로 테스트 리포트 및 관련 산출물을 작성·관리하였습니다. 또한 다양한 검증 Tool을 활용하여 테스트 실행 및 결과를 관리하고, Vector 서버 기반의 테스트 환경을 구축하여 통합 테스트 수행과 결과 관리를 지원하였습니다.

+
+
+

LDM 제어기 검증

+

LED Driving Module

+

차량용 LDM 제어기의 안정적인 동작과 기능 신뢰성을 확보하기 위해 전원 및 입력 신호, 출력 특성, 부하 대응, 주요 Test Point 및 기능 동작에 대한 종합적인 검증을 수행하였습니다. 초기 전원 인가에 따른 제어기의 동작 안정성을 확인하고, Duty 및 Frequency 변화에 따른 PWM 신호 특성과 Decade 저항 변화에 대한 입력 대응성을 검증하여 다양한 입력 조건에서의 정상 동작 여부를 확인하였습니다. 전 채널의 LED 부하 출력 기능을 검증하고 채널별 특성 전류를 측정하여 데이터를 체계적으로 기록하였으며, Electronic Load와 연동한 테스트를 통해 다양한 부하 조건에서의 출력 특성과 안정성을 검증하였습니다. 또한 주요 Test Point의 전압 및 신호 파형을 측정하고 데이터를 정량화하여 Oscilloscope 기반으로 이상 동작의 원인과 결함 발생 요인을 분석하였습니다. 고객사에서 제공한 Test Case를 기반으로 제어기의 주요 기능에 대한 종합적인 동작 검증을 수행하고, 테스트 과정에서 발생한 이상 동작 및 불량 현상에 대해 원인을 추적하여 문제점을 분석하였습니다. 테스트 결과와 결함 원인 분석 내용을 정량적인 데이터로 정리하고, 종합 분석 리포트 및 결과 보고서를 산출하여 제어기의 기능 안정성과 품질 신뢰성을 객관적으로 검증할 수 있도록 지원하였습니다.

+
+
+

공조제어기 ES 사양 검증

+

H-VAC Controller ES Specification Verification

+

차량 공조제어기의 전장 소프트웨어 안정성과 보안성을 확보하기 위해 진단통신, 하드웨어 보안 모듈 및 소프트웨어 업데이트 기능에 대한 ES 사양 검증을 수행하였습니다. UDS 기반 진단통신 평가를 통해 제어기와 진단 시스템 간 통신 사양 및 주요 진단 기능을 검증하고, 차량 전장 시스템의 안정적인 진단 환경을 확보하였습니다. HSM(Hardware Security Module) 기반 보안 모듈에 대한 검증을 비롯하여 암호화 알고리즘, Secure Boot 및 소프트웨어 무결성 검증을 수행함으로써 제어기 소프트웨어의 보안성과 신뢰성을 확보하였습니다. 또한 TP 제어기의 보안 리프로그래밍(Secure Flash 2.0) 기능을 검증하여 소프트웨어 업데이트 과정에서의 보안 요구사항과 정상적인 리프로그래밍 동작을 확인하였습니다. 1·2세대 유·무선 소프트웨어 업데이트 시스템(OTA)에 대한 기능 및 통신 검증을 수행하고, H-OTA Studio와 연계하여 다양한 OTA 시나리오를 구성하고 실제 통신 과정을 검증하였습니다.

+
+
+

전장 SW 로그정보 취득 및 리프로그래밍

+

Log Information Acquisition & Reprogramming

+

현대자동차 울산공장, 남양연구소 등 전국 주요 SITE를 직접 방문하여 실차 기반의 전장 SW Re-Work 및 대규모 리프로그래밍 이슈에 대응하고, 차량 전장 시스템의 안정적인 소프트웨어 운영을 지원하였습니다. SOP 단계에서 발생하는 다양한 현장 이슈를 신속하게 분석하고 대응할 수 있도록 로그 정보 취득부터 제어기 업데이트 및 교체까지 실차 중심의 기술 지원 업무를 수행하였습니다. CANalyzer를 활용하여 실차에서 발생하는 각종 CAN 로그 및 전장 시스템 정보를 취득하고 분석하여 문제 상황을 파악할 수 있도록 하였으며, 진단기를 이용하여 다양한 제어기의 소프트웨어 업데이트 및 리프로그래밍을 수행하였습니다. 또한 실차량의 탈거 작업을 통한 BDC(Body Domain Controller) 제어기 교체와 FOB 작업을 통한 스마트 키 보드 교체 및 재설정 등 차량 전장 부품에 대한 현장 작업을 함께 수행하였습니다. 특히, SOP 단계에서 발생한 대규모 리프로그래밍 이슈에 대해 다수의 전문 인력을 현장에 투입하여 전국 각 SITE에서 신속하게 Re-Work를 수행하고, 차량별 상황에 따른 로그 취득·분석 및 제어기 업데이트를 진행하였습니다. 이를 통해 양산 단계에서 발생할 수 있는 전장 SW 이슈에 대한 현장 대응력을 확보하고, 차량의 소프트웨어 및 전장 시스템이 안정적으로 정상화될 수 있도록 지원하였습니다.

+
+
+

순정 NAVI 엔진앱 / HMI 개발

+

Genuine Navigation Engine App / HMI Development

+

현대·기아 차량에 적용되는 순정 내비게이션의 엔진 및 HMI를 개발하고, 브랜드·차종·지역별 요구사항에 유연하게 대응할 수 있는 공통 개발 환경을 구축하였습니다. 코드 일원화를 통해 브랜드 및 차종, 지역에 따라 개별적으로 발생하는 개발 요소를 효율적으로 관리하고, 공통 기능의 재사용성을 높여 내비게이션 개발 및 유지보수의 효율성을 향상시켰습니다. 정적 분석 Tool을 활용하여 소스 코드의 잠재적인 오류와 품질을 점검하고 코드 안정성을 확보하였으며, 내비게이션과 센터 서버 간 실시간 업데이트 기능을 개발하여 최신 정보와 서비스가 차량 내 내비게이션에 신속하게 반영될 수 있도록 구현하였습니다. 또한 차량 시스템과 내비게이션 간 Interface를 개발하여 각 시스템 간 안정적인 데이터 및 기능 연계가 가능하도록 구성하였습니다. 이와 함께 차량의 주행 특성을 고려한 N-mode(서킷) 기능 개발에 참여하여 특수 주행 환경에 대응할 수 있는 내비게이션 기능을 확장하였으며, 지도 화면에 부동산 정보를 연동하여 기존 길안내 중심의 내비게이션에서 다양한 생활·부가 정보를 함께 제공할 수 있도록 기능을 확대하였습니다. 이를 통해 공통 코드 기반의 개발 효율성과 소프트웨어 안정성을 확보하고, 차량 시스템·서버·지도 데이터 등 다양한 요소와의 연계를 통해 현대·기아 순정 내비게이션의 서비스 확장성과 사용자 편의성을 향상시켰습니다.

+
+
+

전장 - ETC

+

자동차 전장 개발 및 컨설팅 이력을 사업명과 사업기간 기준으로 정리한 기타 수행 프로젝트 목록입니다.

+
  • EB AutoSAR 기반 Platform 및 Safety Mechanism SW 개발 · 2026. 04 ~
  • JS TECH KA5 T-CAR BSW 개발 · 2026.01 ~ 2026.03
  • EB Safety Classic AutoSAR Multicore Porting 및 Application 개발 · 2025. 11 ~ 2026.03
  • 현대차 BDC 제어기 전장 SW 로그 분석 및 리프로그래밍 과제 · 2025.09 ~
  • HL KLEMOVE SRR-40DF 제어기 보드 Ethernet Bootloader 개발 · 2025.01 ~ 2025.06
  • HL KLEMOVE 자율주행 ADAS_DRV 제어기 AUTOSAR BSW 개발 · 2024.01 ~ 2025.12
  • JS TECH ASW 컨설팅 · 2023.04 ~ 2023.10
  • 대우전자부품 CCH 제어기 AUTOSAR BSW 컨설팅 · 2024.05 ~ 2024.12
  • SL 2세대 SBCM 제어기 SW 개발 · 2023.12 ~ 2025.03
  • SL AUTOSAR SW 통합 및 비기능 SW 개발 · 2023.05 ~ 2024.12
  • LG전자 VS 사업부 Honda, Toyota, BMW 제어기 Modem BSP 개발 · 2022.04 ~ 2023.07
+
+
+
+

Robotics 로봇 기술 역량

+
+

가이드 및 큐레이팅 봇 개발

+

Guide & Curating Robot Development

+

사용자가 필요한 정보를 쉽고 빠르게 확인하고 목적지까지 편리하게 이동할 수 있도록 가이드봇 UI와 챗봇, AR 기반 길안내 기능을 연계한 가이드 및 큐레이팅 봇을 개발하였습니다. 직관적인 가이드봇 UI와 서비스 화면을 구성하여 사용자가 다양한 안내 정보를 편리하게 확인하고 서비스 기능을 자연스럽게 이용할 수 있도록 구현하였습니다. 챗봇과 연계한 동적 개발을 통해 사용자의 질문과 요청에 따라 필요한 정보를 제공할 수 있도록 구성하였으며, AR 기반 길안내 기능을 적용하여 실제 공간에서 이동 경로와 목적지를 직관적으로 확인할 수 있도록 하였습니다. 또한 QR 기반 접수 정보와 전자카드를 연동하여 별도의 복잡한 절차 없이 접수 및 관련 정보를 확인하고 이용할 수 있는 편의 기능을 제공하였습니다. 이를 통해 단순한 정보 안내를 넘어 챗봇을 통한 정보 제공, AR 기반 공간 안내, QR 및 전자카드 연동 등 다양한 기능을 하나의 서비스로 통합하여 사용자의 정보 접근성과 이동 편의성을 높였습니다. 또한 서비스 특성에 맞는 UI를 구축하여 가이드 및 큐레이팅 서비스의 이용 편의성과 운영 효율성을 향상시킬 수 있는 사용자 중심의 안내 환경을 구현하였습니다.

+
+
+

공기청정기 로봇 개발

+

Air-Purifying Robot Development

+

AI 자율주행 기술을 기반으로 실내 공간을 이동하며 공기질을 관리하고, 사용자와의 상호작용 및 생활 편의 기능까지 제공할 수 있는 공기청정기 로봇을 개발하였습니다. 공간 내 사각지대를 최소화할 수 있도록 자율주행 기반의 이동 청정 기능을 구현하고, 주변 환경을 감지하여 상황에 맞게 대응할 수 있도록 구성함으로써 보다 효율적인 실내 공기 관리 환경을 제공합니다. Google Gemini를 탑재하여 사용자의 간단한 질문이나 안내 요청에 응답하고 일상적인 대화가 가능하도록 구현하였으며, 접촉 없이 약 10초 이내에 체온 등 건강 관련 신호를 확인할 수 있는 기능을 제공하여 공기청정 기능을 넘어 사용자의 일상적인 건강관리까지 지원할 수 있도록 구성하였습니다. 또한 개인정보 보호와 데이터 보안을 고려하여 사용자 데이터가 안전하게 관리될 수 있도록 보안 환경을 적용하였으며, 향후 사용자의 생활 패턴과 요구에 따라 나만의 주치의, 시큐리티 등 다양한 기능을 지속적으로 확장할 수 있는 기반을 마련하였습니다. 이를 통해 공기질 관리와 AI 기반 사용자 인터랙션, 건강 신호 확인, 보안 및 생활 편의 기능을 하나의 로봇에 통합하여 일상 공간에서 다양한 서비스를 제공할 수 있는 지능형 공기청정 로봇 환경을 구현하였습니다.

+
+
+

스마트돌봄 사업 봇 개발

+

Smart Care Service Robot Development

+

아동을 대상으로 실시간 교육과 비대면 상담, 인공지능 기반 학습 및 놀이 활동, 로봇을 활용한 인지·정서 평가를 제공할 수 있도록 스마트돌봄 사업 봇을 개발하였습니다. 화상장비를 활용한 양방향 화상교육 및 비대면 상담 기능을 제공하여 시간과 장소의 제약을 최소화하고, 아동과 교육 및 상담 담당자 간 원활한 실시간 소통이 가능하도록 구성하였습니다. 생성형 인공지능을 활용하여 아동의 학습과 놀이 활동을 지원하는 프로그램을 제공하고, 창의력·어휘력·사고력 향상을 위한 다양한 콘텐츠를 구성하여 아동이 흥미를 가지고 자연스럽게 학습에 참여할 수 있도록 구현하였습니다. 또한 로봇을 활용한 인지·정서 평가 프로그램을 통해 아동의 활동 및 반응을 기반으로 인지능력을 측정하고 관리할 수 있는 기능을 제공하였습니다. 이를 통해 화상 기반 교육 및 상담, 생성형 AI 기반 학습·놀이 서비스, 로봇 기반 인지·정서 평가와 운영 관리 기능을 하나의 환경으로 통합하여 아동의 학습과 돌봄을 효과적으로 지원할 수 있는 스마트돌봄 플랫폼을 구현하였습니다.

+
+
+

로봇 영어 제작 플랫폼

+

AI English Tutoring Robot Platform

+

로봇을 활용하여 아동의 흥미와 참여를 유도하고, 놀이와 학습을 자연스럽게 결합한 영어 학습 환경을 제공할 수 있도록 로봇 영어 제작 플랫폼을 구축하였습니다. 아동이 로봇과 직접 상호작용하며 학습할 수 있도록 활동 감지 및 터치 센서를 적용하여 학습 참여도를 높이고, 안전한 환경에서 언어 학습을 실천할 수 있도록 구성하였습니다. 아동의 행동 및 이용 패턴을 분석하여 개인의 관심과 활동 특성에 맞는 최적화된 정보 서비스를 제공할 수 있도록 구현하였습니다. 화장실 이용 횟수 및 시간대, 시소·그네·미끄럼틀 등 선호하는 놀이 요소와 같은 데이터를 활용하여 아동의 행동 특성을 파악하고, 축적된 데이터를 기반으로 보다 효과적인 학습 및 관리 서비스를 제공할 수 있도록 하였습니다. 또한 관리자 모드를 통해 연령대 및 성별에 따른 학습 콘텐츠를 관리하고, 게임 콘텐츠의 등록 및 운영, 스케줄 관리 등의 기능을 제공하여 관리자가 교육 환경을 효율적으로 운영할 수 있도록 구성하였습니다.

+
+
+
+

Solution 솔루션 기술 역량

+
+

TPMS 통합 솔루션

+

Integrated TPMS Solution

+

TPMS 통합 솔루션은 교육, 산업, 방송 등 다양한 플랫폼 환경에서 발생하는 데이터를 통합적으로 관리하고 분석할 수 있도록 지능형 기술을 적용한 Total Platform Management System 입니다. 빅데이터를 기반으로 플랫폼에서 생성되는 다양한 데이터를 수집·분석하고, 딥러닝 및 머신러닝 기술을 활용하여 단순한 현황 및 통계 정보 제공을 넘어 데이터 기반의 소요예측과 미래지향적 분석 기능을 구현하였습니다. 이를 통해 반복적으로 수행되는 관리 업무를 자동화할 수 있고, 축적된 데이터를 기반으로 주요 업무 및 운영 현황을 지능적으로 분석할 수 있습니다. 또한 플랫폼별로 분산되어 있는 데이터를 체계적으로 관리하고 통계 및 분석 결과를 제공함으로써 운영 효율성을 높이고, 데이터에 기반한 의사결정이 가능하도록 구성하였습니다. 특히, 지능형 데이터 분석을 통해 향후 발생 가능한 수요와 운영 결과를 예측할 수 있는 기반을 마련하여, 교육·산업·방송 분야의 다양한 플랫폼 운영 환경에 대응할 수 있는 미래지향적인 통합 관리 솔루션으로 활용될 수 있도록 개발하였습니다.

+
+
+

위치 기반 광고 송출 시스템

+

Location Based Advertisement Broadcasting System

+

버스, 지하철 등 대중교통 이용 환경에서 사용자의 위치와 이동 경로를 기반으로 맞춤형 광고 및 교통 정보를 제공할 수 있도록 위치 기반 관제 및 광고 송출 시스템을 TPMS 통합 솔루션으로 구축하였습니다. GPS 기반의 위치 정보를 활용하여 대중교통의 이동 상황을 실시간으로 분석하고, 이용자의 이동 위치에 따라 도착 정류장 안내, 정류장 주변 맞춤형 광고, 도착 정류장 주변의 연계 교통 정보 등 위치와 상황에 최적화된 콘텐츠를 제공할 수 있도록 구현하였습니다. 이를 통해 단순한 광고 송출을 넘어 대중교통 이용자의 이동 상황과 연계된 정보성 콘텐츠를 함께 제공하여 광고의 활용성과 서비스 편의성을 높였습니다. 특히, GPS 좌표의 흔들림 현상과 각 정류장 및 버스의 이동 방향을 정밀하게 분석하기 위해 벡터의 내적을 활용한 자체 개발 버스 GPS 엔진을 적용하여 버스의 실제 이동 방향과 정류장 간의 위치 관계를 분석하고, 현재 위치 및 도착 정류장을 보다 정확하게 판단할 수 있도록 하여 위치 기반 광고 송출과 교통 정보 제공의 정확도를 향상시켰습니다.

+
+
+

사내방송 시스템

+

Internal Office Broadcasting & Monitoring System

+

전사 및 지점, 부서 단위의 사내 방송을 효율적으로 운영하고 관리할 수 있도록 통합 모니터링 기반의 사내방송 시스템을 TPMS 통합 솔루션으로 구축하였습니다. 방송 현황과 각종 방송 장비의 연결 및 운영 상태를 한눈에 확인할 수 있도록 구성하여 관리자가 전체 방송 환경을 효율적으로 모니터링할 수 있도록 지원하였습니다. 원격 전원 및 음량 제어, 장비 재시작 등의 기능을 제공하여 현장에 직접 방문하지 않고도 장비를 관리할 수 있도록 하였으며, 지점 및 부서별 장비 그룹 관리와 방송 스케줄 설정을 통해 대상과 상황에 맞는 맞춤형 방송 정보를 전달할 수 있도록 구현하였습니다. 또한 영상, 이미지, 웹, 오디오 등 다양한 형태의 콘텐츠를 지원하여 사내 공지 및 정보 전달의 효과를 높였습니다. 콘텐츠 동기화 기능과 장비별 상태 확인 기능을 통해 전사 방송 콘텐츠의 일관성을 유지하고, 방송 장비의 운영 상태를 체계적으로 관리할 수 있도록 구성하였습니다. 이를 통해 사내방송 운영에 필요한 관리 업무를 통합하고 현장 관리 부담을 최소화하여, 안정적인 방송 서비스 운영과 전반적인 관리 효율성을 향상시켰습니다.

+
+
+

자동차 포토존 3D 촬영 솔루션

+

Vehicle Photozone 3D Video Capture System

+

자동차 포토존 3D 촬영 솔루션은 자동차를 다양한 각도에서 촬영하여 차량의 외관을 360도 콘텐츠로 제작하고, 이를 온라인 차량 소개 및 비대면 상담에 활용할 수 있는 Hardware & Software 종합 시스템 솔루션 입니다. 턴테이블을 활용하여 차량을 일정한 각도로 회전시키면서 촬영함으로써 촬영 각도와 품질의 일관성을 확보하고, 키오스크를 통해 촬영 과정을 간편하게 조작할 수 있도록 구현하여 작업자의 편의성과 운영 효율성을 높였습니다. 또한 모바일 기기를 촬영 장비로 활용할 수 있도록 구성하여 별도의 전문 촬영 장비에 대한 부담을 줄이고 다양한 환경에서 유연하게 운영할 수 있도록 하였습니다. 차량을 반복적으로 이동하거나 촬영자가 차량 주변을 직접 이동하며 촬영해야 하는 작업을 최소화하여 촬영에 소요되는 시간과 작업 부담을 줄였으며, 촬영된 이미지를 기반으로 3D 모바일 뷰어와 연계하여 실제 차량을 다양한 각도에서 확인할 수 있는 콘텐츠를 제공합니다. 이를 통해 오프라인 전시 및 촬영 중심의 차량 소개 방식을 온라인 환경으로 확장하고, 고객이 시간과 장소의 제약 없이 차량의 외관을 확인하고 비대면 상담까지 활용할 수 있는 디지털 차량 콘텐츠 환경을 구현하였습니다.

+
+
+

3D 촬영 관리 시스템

+

3D Video Capture Management System

+

중고차 매물 등록 과정에서 발생하는 현장 촬영과 등록 업무를 효율적으로 관리할 수 있도록 촬영 관리 시스템을 자동차 포토존 3D 촬영 솔루션으로 구축하였습니다. 현장에서 차량 확인부터 촬영, 사진 관리 및 매물 등록에 필요한 업무를 하나의 흐름으로 처리할 수 있도록 구성하여 반복적인 정보 입력과 사진 파일 전달 등의 불필요한 작업을 최소화하고 매물 등록에 소요되는 업무 시간을 단축하였습니다. 차량별로 등록에 필요한 필수 촬영 장면과 촬영 가이드라인을 모바일 앱에서 제공하여 작업자가 촬영 순서와 기준을 쉽게 확인할 수 있도록 하였으며, 이를 통해 작업자에 따라 달라질 수 있는 촬영 결과의 편차를 줄이고 일관된 품질의 매물 이미지를 확보할 수 있도록 구현하였습니다. 또한 촬영된 사진을 차량 정보와 연계하여 체계적으로 관리할 수 있도록 하고, 촬영 결과의 임시저장 및 업로드 상태를 앱과 관리자 시스템에서 확인할 수 있도록 구성하였습니다. 기존에 등록된 차량의 정보와 촬영 현황 또한 앱 및 관리자 시스템을 통해 확인할 수 있도록 하여 현장 작업과 관리 업무 간의 연계성을 높이고, 중고차 매물 등록 업무의 전반적인 운영 효율성과 관리 편의성을 향상시켰습니다.

+
+
+

보고웍스 플랫폼

+

Automation Reporting and Management Platform Solution

+

보고웍스 플랫폼은 프로젝트의 작업 진행 현황과 관련 자료를 통합적으로 관리하고 관리자와 현업 종사자 간의 원활한 업무 소통을 지원할 수 있는 솔루션입니다. 실시간 작업 진행 상황을 공유하고 확인할 수 있도록 구성하여 프로젝트 수행 과정에서 발생하는 업무 현황을 신속하게 파악하고 효율적으로 협업할 수 있도록 하였습니다. 프로젝트 유형별 관리 기능을 통해 다양한 프로젝트의 업무와 진행 상황을 체계적으로 관리할 수 있도록 하였으며, 자동보고서 기능을 적용하여 프로젝트 진행 과정에서 필요한 보고서를 효율적으로 생성하고 관리할 수 있도록 구현하였습니다. 이를 통해 반복적인 보고서 작성 업무를 줄이고 보고 내용의 정확성과 신뢰성을 높일 수 있도록 지원하였습니다. 또한 프로젝트별로 생성되는 각종 자료와 업무 정보를 데이터화하여 체계적으로 축적하고 관리할 수 있도록 구성하였습니다. 이를 통해 프로젝트 종료 및 담당자 변경 시 필요한 자료를 효율적으로 공유하고 인수인계할 수 있는 환경을 제공하며, 축적된 프로젝트 정보를 기반으로 업무 연속성을 확보하고 전반적인 프로젝트 관리 효율성을 향상시켰습니다.

+
+
+

지능형 학생관리 통합 플랫폼

+

Intelligent Student Management Integrated Platform

+

지능형 학생관리 통합 플랫폼은 학생관리 업무의 체계적인 운영과 효율적인 관리를 위해 상호호환되는 다양한 관리 시스템을 하나로 통합한 지능형 솔루션입니다. 학생의 현재 상태와 출입 및 퇴실 정보를 통합적으로 관리하고, 관리자와 학생 부모가 관련 정보를 실시간으로 확인하고 소통할 수 있도록 구성하여 학생 관리의 신속성과 편의성을 높였습니다. 관리자 간에도 학생 및 업무 관련 정보를 원활하게 전달하고 공유할 수 있도록 협업 기능을 제공하여 담당자 간 업무 연계성을 강화하였으며, 실시간으로 변화하는 학생 정보를 기반으로 보다 효율적인 관리와 대응이 가능하도록 구현하였습니다. 또한 전체 관리체계를 5개의 주요 분야로 세분화하여 각 관리자가 담당 업무에 집중하고 해당 영역을 보다 체계적이고 심도 있게 관리할 수 있도록 구성하였습니다. 이를 통해 분산되어 있던 학생관리 업무와 정보를 통합하고, 관리자와 학생 부모 간의 실시간 정보 공유 및 관리자 간 협업을 지원하여 학생관리 업무의 효율성과 운영 편의성을 향상시켰습니다.

+
+
+

해안 스카일 레일 운영 관제

+

Costline Sky Rail Operation Monitoring System

+

해안 스카이레일 관제 솔루션은 스카이레일의 운행 상태를 실시간으로 모니터링 하고 통합 관리하기 위한 스마트 관제 시스템입니다. 차량의 위치와 운행 상태를 실시간으로 확인할 수 있으며, 운행 정보와 설비 상태를 통합 관제하여 안전한 운행과 효율적인 운영 관리를 할 수 있도록 개발하였습니다. 차량은 배터리 상태, 속도, 운행 위치를 관제할 수 있으며 설비의 이상 상태를 실시간으로 감지하여 관제자에게 알려줍니다. 또한, 운행 이력과 데이터를 통해 운영 분석을 지원하여 원활한 유지보수를 지원할 수 있도록 하였습니다.

+
+
+
+

SI 웹·앱 개발 사례

+
+

AUTOSAR 통합 자동화 플랫폼

+

AutoSAR Integration Automation Platform

+

AUTOSAR 플랫폼을 기반으로 차량용 ECU 기능 개발에 필요한 모듈을 체계적으로 개발하고, 이를 하나의 환경에서 통합할 수 있는 통합 자동화 플랫폼을 구축하였습니다. ECU 기능 구현에 필요한 각종 소프트웨어 모듈을 기반으로 개발 및 통합 과정을 진행할 수 있도록 구성하여 차량용 소프트웨어 개발 환경의 효율성을 높였습니다. AUTOSAR 표준 기반의 플랫폼 환경에서 ECU 기능에 필요한 모듈을 개발하고 각각의 기능을 통합함으로써, 개별적으로 개발되는 소프트웨어 구성 요소를 체계적으로 관리하고 통합할 수 있도록 구현하였습니다. 이를 통해 ECU 기능 개발 과정에서 발생하는 반복적인 통합 작업을 효율적으로 관리하고, AUTOSAR 기반 차량용 소프트웨어의 개발 및 통합 업무를 안정적으로 수행할 수 있는 기반을 마련하였습니다.

+
+
+

변리사 미팅 플랫폼

+

국내외 특허 출원 및 해외 특허 확장을 위해 필요한 각국·각 분야의 변리사와 전문가를 연결하고, 미팅부터 업무 진행까지 원스톱으로 지원할 수 있는 위멧 변리사 미팅 플랫폼을 구축하였습니다. 기존 이메일이나 지인 추천, 컨퍼런스 등을 통해 개별적으로 진행되던 변리사 탐색 및 미팅 과정을 플랫폼 기반으로 전환하여 보다 효율적인 업무 진행이 가능하도록 구성하였습니다. 기계, 통신 등 특허 분야별로 전문성을 갖춘 변리사 정보를 세분화하여 제공함으로써 사용자가 필요한 분야의 전문가를 한눈에 확인하고, 업무 목적에 적합한 변리사를 쉽고 빠르게 탐색할 수 있도록 구현하였습니다. 또한 국내외 특허 업무에 필요한 전문가 연결 과정을 체계적으로 관리할 수 있도록 하여 기존의 복잡하고 비효율적인 전문가 탐색 및 커뮤니케이션 과정을 간소화하였습니다. 이를 통해 특허 출원 및 해외 확장 과정에서 필요한 전문 인력과의 연결성을 높이고, 전문가 탐색부터 미팅까지 이어지는 업무 프로세스를 효율적으로 지원하여 특허 관련 업무의 편의성과 신속성을 향상시킬 수 있는 플랫폼 환경을 제공하였습니다.

+
+
+

해외법인(중국&멕시코) 구매시스템 웹 표준화 전환

+

Overseas Subsidiary (China, Mexico) Procurement System Web Conversion Project

+

해외법인(중국, 멕시코)에서 운영 중인 레거시 FLEX 기반 구매시스템을 HTML5 기반의 웹 표준 환경으로 전환하고, 서버 및 DBMS 환경까지 Conversion을 수행하여 글로벌 구매 업무의 안정적인 운영 기반을 구축하였습니다. 기존 FLEX 기반 시스템을 HTML5 웹 표준 기술로 전환하여 특정 기술 환경에 대한 의존성을 개선하고, 다양한 웹 환경에서 안정적으로 서비스를 이용할 수 있도록 시스템을 현대화하였습니다. 또한 기존 업무 기능과 데이터를 안정적으로 유지하면서 서버 및 DBMS 환경을 함께 Conversion하여 시스템 운영 환경의 전반적인 표준화와 효율성을 확보하였습니다. 특히, 중국과 멕시코 해외법인에서 사용되는 구매시스템을 대상으로 웹 표준화 전환과 서버·DBMS 환경 Conversion을 성공적으로 수행함으로써 기존 레거시 시스템의 기술적 제약을 개선하고, 향후 시스템 유지보수 및 확장이 용이한 웹 기반 환경을 마련하였습니다. 이를 통해 해외법인의 구매 업무 연속성을 확보하고 글로벌 시스템 운영의 안정성과 관리 효율성을 향상시켰습니다.

+
+
+

포토카드 키오스크 및 관리 시스템

+

Photocard Kiosk and Management System

+

공연장·전시회·팝업스토어 등 다양한 현장에서 방문객이 별도의 지원 없이 이미지 선택부터 카드 편집, 결제, 포토카드 출력까지 전 과정을 이용할 수 있는 무인 포토카드 제작 서비스입니다. 현장 키오스크와 결제 장치, 포토 프린터를 연동하여 편리하고 안정적인 무인 제작 환경을 제공하며, 웹 기반 관리자 시스템을 통해 콘텐츠와 출력 데이터를 통합 관리할 수 있게 개발하였습니다. 특히 관리 시스템을 현장에 맞춰 개발하여 출력 이력과 데이터 관리가 원활하게 이루어질 수 있도록 하였습니다.

+
+
+

AI 기반 메디컬 뷰티 플랫폼

+

AI Based Medical Beauty Service Platform

+

생성형 인공지능을 활용하여 사용자의 관심과 요구에 맞는 병원 및 시술 정보를 추천하고, 병원 선택부터 예약과 결제까지 하나의 플랫폼에서 진행할 수 있는 AI 기반 메디컬 뷰티 플랫폼을 구축하였습니다. 사용자 맞춤형 추천 기능을 통해 개인의 관심 분야와 조건에 적합한 성형외과 및 시술 정보를 제공하고, 위치정보를 기반으로 사용자 인근의 성형외과 정보를 확인할 수 있도록 구성하여 병원 탐색의 편의성을 높였습니다. 또한 성형외과 전용 시술정보와 예약관리 기능을 제공하고, 고객 피드백을 체계적으로 관리할 수 있도록 하여 병원과 고객 간의 효율적인 소통을 지원하였습니다. 특히, 병원 및 시술 정보 탐색부터 예약, 결제까지의 과정을 하나의 서비스로 연결한 원스톱 예약·결제 시스템을 구현하여 사용자의 서비스 이용 절차를 간소화하였습니다. 이를 통해 생성형 AI 기반의 개인화된 정보 추천과 위치 기반 병원 검색, 시술정보 및 예약·결제 서비스를 통합하여 메디컬 뷰티 분야의 사용자 편의성과 서비스 접근성을 높이고, 병원 운영 및 고객관리의 효율성을 향상시킬 수 있는 플랫폼 환경을 제공하였습니다.

+
+
+

자녀 안심 플랫폼

+

Children Security Zone Management Platform

+

자녀의 스마트폰 사용 환경을 안전하게 관리하고 보호자가 원격으로 자녀의 상태를 관리할 수 있도록 스마트폰 제어 및 위치 기반 기능을 통합한 자녀 안심 플랫폼을 구축하였습니다. 스마트폰 사용시간 제어와 원격 관리 기능을 제공하여 보호자가 자녀의 스마트폰 이용 환경을 효율적으로 관리할 수 있도록 구성하였습니다. GPS 기반의 자녀 안심존 관리 기능을 통해 지정된 안전 구역의 설정 및 자녀의 출입 여부를 확인할 수 있도록 하고, 출입 상황을 보호자에게 통지하여 자녀의 위치 및 이동 상황을 보다 편리하게 확인할 수 있도록 구현하였습니다. 또한 스마트폰 카메라 장치 제어 기술을 적용하여 불법적인 촬영 및 몸캠 피해를 예방할 수 있는 기능을 제공하고, 스마트폰 화면 제어 기술을 기반으로 사이버 폭력 및 음란 문자와 같은 유해 콘텐츠를 감지할 수 있도록 구성하였습니다. 자이로센서 기술을 활용하여 자녀가 보행 중 스마트폰을 사용하는 상황을 감지하고 스마트폰 잠금을 활성화하는 스몸비 방지 기능을 구현하였으며, Android Framework 제어 기술을 적용하여 스마트폰 권한 및 애플리케이션을 원격으로 관리할 수 있도록 하였습니다. 이를 통해 스마트폰 사용 관리, 위치 및 출입 관리, 유해 콘텐츠 대응, 보행 안전, 애플리케이션 관리 등 자녀 보호에 필요한 다양한 기능을 하나의 플랫폼으로 통합하여 보호자의 관리 편의성과 자녀의 스마트폰 이용 안전성을 향상시켰습니다.

+
+
+

룸 매니징 플랫폼

+

Hotel Room Managing Service Platform

+

호텔 객실에서 제공되는 다양한 콘텐츠와 객실 제어, 고객 편의 서비스를 하나의 플랫폼으로 통합하여 호텔 운영의 효율성과 고객 서비스 품질을 향상시킬 수 있는 룸 매니징 플랫폼을 구축하였습니다. 통합 리모컨을 통해 실시간 TV와 OTT 서비스를 편리하게 이용할 수 있도록 하고, 조명 및 객실 제어 기능을 연계하여 고객이 객실 내 주요 기능을 손쉽게 관리할 수 있도록 구성하였습니다. 객실 초기 화면에 호텔 공지 및 안내사항을 제공하여 고객이 필요한 정보를 사전에 확인할 수 있도록 함으로써 불필요한 문의를 줄이고, 호텔 소개와 시설 안내, 예약 서비스 등을 통해 호텔 이용에 필요한 정보를 편리하게 제공하였습니다. 또한 대실 및 숙박 연장, 셀프 체크아웃 기능을 지원하여 프런트 업무를 간소화하고 고객이 원하는 시간에 직접 서비스를 이용할 수 있도록 구현하였습니다. 고객의 편의와 만족도를 높일 수 있도록 다양한 상품 및 룸 서비스를 제공하고, 비대면 결제와 비대면 배송 시스템을 연계하여 객실에서 주문부터 결제 및 상품 수령까지 편리하게 이용할 수 있도록 구성하였습니다. 이를 통해 객실 제어부터 콘텐츠 이용, 호텔 정보 확인, 예약 및 결제, 룸 서비스까지 고객에게 필요한 서비스를 하나의 플랫폼에서 제공하고, 동시에 비대면 업무와 부가 서비스 판매를 통해 호텔 운영 효율성과 고객 편의성, 수익성을 함께 향상시킬 수 있는 통합 객실 서비스 환경을 구현하였습니다.

+
+
+

스마트 트래킹 시스템

+

Smart Location Tracking System

+

스마트폰과 귀중품의 분실을 예방하고 분실 상황에서도 쉽고 빠르게 위치를 확인할 수 있도록 스마트폰과 스마트 트래커를 연계한 스마트 트래킹 시스템을 구축하였습니다. 스마트폰과 ‘I’m Here’가 일정 거리 이상 멀어지는 상황을 감지하여 양쪽에서 알림을 제공함으로써 스마트폰뿐만 아니라 지갑, 가방, 자동차 키 등 휴대가 잦은 귀중품의 분실을 사전에 방지할 수 있도록 구성하였습니다. 귀중품을 분실한 경우에는 스마트폰의 Smart[Home] App과 연계하여 분실 위치를 지도에서 확인할 수 있도록 하였으며, 스마트폰과 스마트 트래커가 가까운 위치에 있는 경우에는 트래커 버튼을 연속으로 두 번 눌러 스마트폰에서 알림음이 울리도록 하여 주변에서 스마트폰을 쉽게 찾을 수 있도록 구현하였습니다. 반대로 귀중품의 경우에도 Smart[Home] App에서 해당 트래커를 선택하는 것만으로 위치를 확인하고 찾을 수 있도록 구성하여 양방향 탐색 기능을 제공합니다. 또한 공항 수하물 수취 과정에서는 스마트폰과 수하물 간의 거리가 가까워지는 상황을 감지하여 스마트폰에서 알림음을 제공함으로써 수하물 도착 여부를 보다 편리하게 확인할 수 있도록 하였습니다. 이를 통해 거리 기반 알림, 위치정보, 스마트폰 연계 기능을 활용하여 일상생활 속 스마트폰 및 귀중품의 분실을 예방하고, 필요한 경우 신속하게 위치를 확인할 수 있는 사용자 중심의 스마트 트래킹 환경을 구현하였습니다.

+
+
+
+

Certifications 특허 기술 역량

+
+

VOISO CMS 시스템 관련 특허증

+

VOISO CMS 시스템과 관련된 특허를 취득하여 데이터 처리 및 관리 기술에 대한 지식재산을 확보했습니다.

+
+
+
+ +
+ + + + + + + diff --git a/contact.html b/contact.html new file mode 100644 index 0000000..9417908 --- /dev/null +++ b/contact.html @@ -0,0 +1,138 @@ + + + + + + + Contact · MOBIPINTECH + + + + + + + + + + +
+
+

Contact

+

문의하기

+

+ 전장 소프트웨어, 내비/HMI, AI·IoT 플랫폼, 서비스 구축에 대한 문의를 남겨주세요. +

+
+ +
+
+
+ Head Office +

대구 본사

+

대구광역시 북구 경대로17길 47, 8층 803호
(복현동, IT융합산업빌딩)

+
+
+ Seoul Office +

서울 사무소

+

서울특별시 강남구 논현로 416
운기빌딩 6층

+
+
+ Office Hour +

평일 09:00 - 18:00

+

대표번호 053-214-0592

+
+
+ +
+ + + + + + + + + + +
+
+
+ + + + + + + + diff --git a/css/styles.css b/css/styles.css new file mode 100644 index 0000000..8d2d98b --- /dev/null +++ b/css/styles.css @@ -0,0 +1,3194 @@ +/* 공통: 색상, 기본 요소, 헤더와 네비게이션 */ +:root { + --bg: #07090d; + --bg-soft: #10141b; + --panel: rgba(16, 20, 27, .78); + --panel-solid: #121821; + --line: rgba(255, 255, 255, .14); + --line-strong: rgba(255, 255, 255, .26); + --text: #f5f7fb; + --muted: #aab3c2; + --dim: #697484; + --accent: #9ee9ff; + --accent-2: #67f0b5; + --warn: #ffca75; + --max: 1180px; + --ease: cubic-bezier(.2, .8, .2, 1); +} + +* { + box-sizing: border-box; +} + +html { + scroll-behavior: smooth; +} + +body { + margin: 0; + background: var(--bg); + color: var(--text); + font-family: "Pretendard Variable", Pretendard, "Noto Sans KR", system-ui, sans-serif; + letter-spacing: 0; + overflow-x: hidden; + word-break: keep-all; + overflow-wrap: break-word; +} + +body.capabilities-body { + overflow: hidden; +} + +a { + color: inherit; + text-decoration: none; +} + +button, +input, +select, +textarea { + font: inherit; +} + +button { + color: inherit; +} + +.site-header { + position: fixed; + top: 0; + left: 0; + right: 0; + z-index: 20; + display: flex; + align-items: center; + justify-content: space-between; + height: 72px; + padding: 0 clamp(18px, 4vw, 54px); + background: linear-gradient(180deg, rgba(7, 9, 13, .88), rgba(7, 9, 13, .48)); + border-bottom: 1px solid transparent; + backdrop-filter: blur(18px); + transition: background .28s var(--ease), border-color .28s var(--ease); +} + +.site-header.is-scrolled { + background: rgba(7, 9, 13, .9); + border-color: var(--line); +} + +.brand { + display: inline-flex; + align-items: center; + gap: 12px; + font-size: 13px; + font-weight: 850; + letter-spacing: .16em; +} + +.brand-logo { + display: block; + width: 112px; + height: auto; +} + +.desktop-nav { + display: flex; + align-items: center; + gap: 4px; +} + +.desktop-nav a { + padding: 10px 14px; + color: var(--muted); + font-size: 14px; + border: 1px solid transparent; + border-radius: 999px; + transition: color .2s var(--ease), border-color .2s var(--ease), background .2s var(--ease); +} + +.desktop-nav a:hover, +.desktop-nav a[aria-current="page"] { + color: var(--text); + border-color: var(--line); + background: rgba(255, 255, 255, .05); +} + +.nav-toggle { + display: none; + width: 42px; + height: 42px; + border: 1px solid var(--line); + border-radius: 6px; + background: rgba(255, 255, 255, .04); + align-items: center; + justify-content: center; + flex-direction: column; + gap: 5px; + cursor: pointer; +} + +.page-dots { + position: fixed; + z-index: 12; + top: 50%; + right: clamp(26px, 4vw, 68px); + display: grid; + justify-items: center; + gap: 3px; + width: 50px; + padding: 13px 8px; + border: 1px solid rgba(255, 255, 255, .1); + border-radius: 999px; + background: rgba(6, 15, 18, .56); + box-shadow: 0 10px 30px rgba(0, 0, 0, .18), inset 0 1px rgba(255, 255, 255, .06); + backdrop-filter: blur(12px); + transform: translateY(-50%); +} + +.page-dot { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 32px; + min-height: 17px; + padding: 0; + border: 0; + background: transparent; + cursor: pointer; +} + +.page-dot-mark { + width: 12px; + height: 2px; + border-radius: 999px; + background: rgba(255, 255, 255, .32); + box-shadow: 0 0 0 1px rgba(0, 0, 0, .08); + transition: width .2s var(--ease), height .2s var(--ease), background .2s var(--ease), box-shadow .2s var(--ease); +} + +.page-dot:hover .page-dot-mark, +.page-dot:focus-visible .page-dot-mark { + width: 20px; + background: rgba(255, 255, 255, .72); +} + +.page-dot.is-active .page-dot-mark { + width: 28px; + height: 3px; + background: #fff; + box-shadow: 0 0 12px rgba(158, 233, 255, .5); +} + +.page-dot-label { + position: absolute; + top: 50%; + right: calc(100% + 16px); + width: max-content; + max-width: 180px; + padding: 7px 10px; + border-radius: 4px; + background: rgba(7, 9, 13, .9); + color: #fff; + font-size: 13px; + font-weight: 750; + line-height: 1.25; + text-align: right; + white-space: nowrap; + opacity: 0; + pointer-events: none; + transform: translate(6px, -50%); + transition: opacity .18s var(--ease), transform .18s var(--ease); +} + +.page-dot-label::after { + content: ""; + position: absolute; + top: 50%; + right: -5px; + width: 10px; + height: 10px; + background: inherit; + transform: translateY(-50%) rotate(45deg); +} + +.page-dot:hover .page-dot-label, +.page-dot:focus-visible .page-dot-label { + opacity: 1; + transform: translate(0, -50%); +} + +.nav-toggle span { + width: 18px; + height: 2px; + background: var(--text); + transition: transform .25s var(--ease), opacity .2s var(--ease); +} + +.nav-toggle.is-open span:first-child { + transform: translateY(7px) rotate(45deg); +} + +.nav-toggle.is-open span:nth-child(2) { + opacity: 0; +} + +.nav-toggle.is-open span:last-child { + transform: translateY(-7px) rotate(-45deg); +} + +.mobile-menu { + position: fixed; + z-index: 19; + top: 72px; + left: 0; + right: 0; + bottom: 0; + display: none; + padding: 24px 28px max(24px, env(safe-area-inset-bottom)); + background: #0b1013; + overflow-y: auto; + overscroll-behavior: contain; + visibility: hidden; + opacity: 0; + transform: translateY(-12px); + transition: opacity .28s var(--ease), transform .35s var(--ease), visibility .35s; +} + +.mobile-menu.is-open { + visibility: visible; + opacity: 1; + transform: translateY(0); +} + +.mobile-menu > a { + position: relative; + display: grid; + grid-template-columns: minmax(0, 1fr) 24px; + align-content: center; + gap: 7px 16px; + min-height: 112px; + padding: 20px 0; + color: var(--text); + border-bottom: 1px solid var(--line); + opacity: 0; + transform: translateY(16px); + transition: opacity .3s var(--ease), transform .4s var(--ease), color .2s; +} + +.mobile-menu.is-open > a { + opacity: 1; + transform: translateY(0); + transition-delay: calc(var(--menu-index) * 45ms); +} + +.mobile-menu-label { + grid-column: 1; + color: var(--dim); + font-size: 12px; + line-height: 1.4; +} + +.mobile-menu-title { + grid-column: 1; + font-size: 30px; + font-weight: 700; + line-height: 1.25; +} + +.mobile-menu > a img { + grid-column: 2; + grid-row: 1 / 3; + align-self: center; + width: 24px; + height: 24px; + filter: brightness(0) invert(1); + opacity: .5; +} + +.mobile-menu > a[aria-current="page"], +.mobile-menu > a:hover { + color: var(--accent-2); +} + +.mobile-menu > a[aria-current="page"] .mobile-menu-label { + color: var(--accent-2); +} + +.mobile-menu > a[aria-current="page"]::before { + content: ""; + position: absolute; + left: -14px; + top: 50%; + width: 3px; + height: 26px; + background: var(--accent-2); + transform: translateY(-50%); +} + +.mobile-menu-signature { + display: flex; + flex-wrap: wrap; + justify-content: space-between; + gap: 12px; + margin-top: auto; + padding-top: 32px; + color: var(--muted); + font-size: 11px; + line-height: 1.5; +} + +.mobile-menu-signature a { + color: var(--accent); + font-size: 12px; +} + +body.mobile-navigation-open { + overflow: hidden; +} + +@media (prefers-reduced-motion: reduce) { + .mobile-menu, + .mobile-menu > a, + .nav-toggle span { + transition: none; + } +} + +/* 홈 */ +.home-hero { + min-height: 100svh; + position: relative; + overflow: hidden; +} + +.hero-media, +.feature-bg { + position: absolute; + inset: 0; + background-position: center; + background-size: cover; + transform: scale(1.02); +} + +.hero-media { + background-image: + linear-gradient(90deg, rgba(7, 9, 13, .94) 0%, rgba(7, 9, 13, .66) 38%, rgba(7, 9, 13, .18) 72%), + linear-gradient(180deg, rgba(7, 9, 13, .1), rgba(7, 9, 13, .9)), + url("../assets/images/automotive/automotive_05_background.png"); + animation: slow-zoom 18s ease-in-out infinite alternate; +} + +.hero-grid { + position: relative; + z-index: 1; + width: min(var(--max), calc(100% - 48px)); + min-height: 100svh; + margin: 0 auto; + display: grid; + grid-template-columns: minmax(0, 1fr) 300px; + align-items: end; + gap: 36px; + padding: 132px 0 104px; +} + +.hero-copy { + max-width: 770px; +} + +.eyebrow, +.section-label { + margin: 0; + color: var(--accent); + font-size: 12px; + font-weight: 800; + letter-spacing: .18em; + text-transform: uppercase; +} + +h1, +h2, +h3, +p { + margin-top: 0; +} + +.hero-copy h1, +.feature-content h1, +.contact-hero h1 { + margin: 18px 0 22px; + font-size: clamp(42px, 6.3vw, 82px); + line-height: 1.05; + letter-spacing: 0; +} + +.hero-lead, +.feature-content p, +.contact-hero p { + max-width: 660px; + color: #d1d7e2; + font-size: clamp(16px, 1.5vw, 20px); + line-height: 1.75; + word-break: keep-all; +} + +.hero-actions { + display: flex; + flex-wrap: wrap; + gap: 10px; + margin-top: 34px; +} + +.button { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 46px; + padding: 0 18px; + border-radius: 6px; + font-weight: 750; + border: 1px solid var(--line); + transition: transform .2s var(--ease), border-color .2s var(--ease), background .2s var(--ease); +} + +.button:hover { + transform: translateY(-2px); + border-color: var(--line-strong); +} + +.button-primary { + color: #031113; + background: linear-gradient(135deg, var(--accent), var(--accent-2)); + border-color: transparent; +} + +.button-ghost { + color: var(--text); + background: rgba(255, 255, 255, .06); +} + +.hero-panel { + display: grid; + gap: 1px; + background: var(--line); + border: 1px solid var(--line); + backdrop-filter: blur(14px); +} + +.hero-panel div { + padding: 22px; + background: rgba(10, 14, 20, .72); +} + +.hero-panel strong { + display: block; + margin-bottom: 6px; + color: var(--accent-2); + font-size: 28px; +} + +.hero-panel span { + color: var(--muted); + font-size: 13px; +} + +.hero-footer { + position: absolute; + z-index: 1; + left: clamp(24px, 4vw, 54px); + right: clamp(24px, 4vw, 54px); + bottom: 22px; + display: flex; + justify-content: space-between; + gap: 20px; + padding-top: 16px; + border-top: 1px solid rgba(255, 255, 255, .25); + color: var(--dim); + font-size: 12px; + font-weight: 750; + text-transform: uppercase; +} + +.section { + width: min(var(--max), calc(100% - 48px)); + margin: 0 auto; + padding: 108px 0; +} + +.intro { + display: grid; + grid-template-columns: 180px minmax(0, 1fr); + gap: 30px; +} + +.intro-copy h2 { + margin-bottom: 18px; + font-size: clamp(30px, 4vw, 54px); + line-height: 1.14; +} + +.intro-copy p { + color: var(--muted); + font-size: 17px; + line-height: 1.85; +} + +.proof-strip { + grid-column: 2; + display: grid; + grid-template-columns: repeat(3, 1fr); + border-top: 1px solid var(--line); + border-left: 1px solid var(--line); +} + +.proof-strip article { + min-height: 240px; + padding: 28px; + border-right: 1px solid var(--line); + border-bottom: 1px solid var(--line); + background: + linear-gradient(180deg, rgba(255, 255, 255, .055), rgba(255, 255, 255, .018)); +} + +.proof-strip span, +.preview-card span, +.office-list span { + display: block; + margin-bottom: 18px; + color: var(--accent); + font-size: 12px; + font-weight: 800; + letter-spacing: .16em; + text-transform: uppercase; +} + +.proof-strip strong { + display: block; + margin-bottom: 14px; + font-size: 23px; + line-height: 1.25; +} + +.proof-strip p { + color: var(--muted); + line-height: 1.7; +} + +.showcase-preview { + display: grid; + grid-template-columns: 1fr 1fr; + min-height: 620px; +} + +.home-body .intro { + width: 100%; + grid-template-columns: minmax(0, 1fr); + gap: 24px; + padding: 72px max(24px, calc((100% - 1180px) / 2)); + align-content: center; +} + +.home-body .intro-copy h2 { + max-width: 1000px; + margin: 0 0 20px; + font-size: 40px; +} + +.home-body .intro-copy p { + max-width: 1000px; + margin: 0; + font-size: 16px; +} + +.home-body .proof-strip { + grid-column: 1; + margin-top: 12px; +} + +.home-body .proof-strip article { + min-height: 0; + padding: 24px; +} + +.home-body .preview-card strong { + max-width: none; + font-size: 34px; + line-height: 1.2; + overflow-wrap: anywhere; +} + +.home-body .preview-card p { + margin: 0; + font-size: 15px; +} + +@media (min-width: 861px) and (min-height: 700px) { + html.home-page { + scroll-snap-type: none; + scroll-padding-top: 72px; + } + + .home-body .home-hero, + .home-body .intro, + .home-body .showcase-preview { + scroll-snap-align: start; + } + + .home-body .intro { + min-height: calc(100dvh - 72px); + padding-top: 48px; + padding-bottom: 48px; + } + + .home-body .showcase-preview { + height: calc(100dvh - 72px); + min-height: 0; + grid-template-rows: repeat(2, minmax(0, 1fr)); + } + + .home-body .preview-card { + min-height: 0; + padding: 28px 40px; + } + + .home-body .preview-card span { + margin-bottom: 12px; + } +} + +@media (max-width: 860px) { + .mobile-menu { + display: flex; + flex-direction: column; + } + + .mobile-menu > a { + flex-shrink: 0; + } + + .home-body .intro-copy h2 { + font-size: 30px; + } + + .home-body .preview-card strong { + font-size: 28px; + } +} + +.preview-card { + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + min-height: 620px; + padding: clamp(28px, 5vw, 72px); + overflow: hidden; + isolation: isolate; +} + +.preview-card::before { + content: ""; + position: absolute; + inset: 0; + z-index: -2; + background-size: cover; + background-position: center; + transition: transform .8s var(--ease), filter .8s var(--ease); +} + +.preview-card::after { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + background: + linear-gradient(180deg, rgba(7, 9, 13, .08), rgba(7, 9, 13, .92)), + linear-gradient(90deg, rgba(7, 9, 13, .8), rgba(7, 9, 13, .1)); +} + +.preview-card:hover::before { + transform: scale(1.06); + filter: saturate(1.12); +} + +.preview-card.automotive::before { + background-image: url("../assets/images/automotive/automotive_01_background.jpeg"); +} + +.preview-card.robotics::before { + background-image: url("../assets/images/robotics/robotics_02_background.png"); +} + +.preview-card.solution::before { + background-image: url("../assets/images/solution/solution_04_background.png"); +} + +.preview-card.si::before { + background-image: url("../assets/images/si/si_05_background.png"); +} + +.preview-card strong { + max-width: 440px; + margin-bottom: 16px; + font-size: clamp(32px, 4.8vw, 64px); + line-height: 1.03; +} + +.preview-card p { + max-width: 520px; + color: #d9dee7; + line-height: 1.75; +} + +/* 기술 역량 */ +.feature-bg { + opacity: 1; + animation: feature-breathe 12s ease-in-out infinite alternate; + background-position: center; + background-size: cover; + transition: opacity .35s var(--ease), transform .8s var(--ease); +} + +@keyframes feature-breathe { + 0% { + filter: brightness(.92) saturate(.96); + transform: scale(1); + } + + 100% { + filter: brightness(1.04) saturate(1.05); + transform: scale(1.035); + } +} + +.feature-bg::after { + content: ""; + position: absolute; + inset: 0; + background: + linear-gradient(90deg, rgba(7, 9, 13, .9) 0%, rgba(7, 9, 13, .62) 42%, rgba(7, 9, 13, .18) 78%), + linear-gradient(180deg, rgba(7, 9, 13, .08), rgba(7, 9, 13, .86)); +} + +.capabilities-workbench.is-table-slide .feature-bg::after { + background: + linear-gradient(180deg, rgba(2, 8, 18, .2), rgba(2, 8, 18, .62)), + rgba(2, 8, 18, .18); +} + +.capabilities-workbench.is-certification-slide { + background: #061322; +} + +.capabilities-workbench.is-certification-slide .feature-bg { + opacity: 0; +} + +.capabilities-workbench.is-certification-slide .feature-bg::after { + display: none; +} + +.feature-content { + position: absolute; + top: 108px; + left: clamp(56px, 7vw, 132px); + z-index: 2; + align-self: flex-start; + width: min(720px, 54%); + max-height: calc(100dvh - 204px); + overflow-y: auto; + overscroll-behavior: contain; + scrollbar-width: thin; +} + +.feature-content h1 { + max-width: 760px; + margin: 14px 0 8px; + font-size: 42px; + line-height: 1.16; +} + +.feature-content p { + white-space: pre-line; + font-size: 15px; + line-height: 1.68; +} + +.feature-content .feature-subtitle { + margin: 0 0 44px; + max-width: 660px; + color: rgba(255, 255, 255, .62); + font-size: 16px; + font-weight: 800; + line-height: 1.35; + white-space: normal; +} + +.feature-object { + position: absolute; + z-index: 1; + right: clamp(190px, 17vw, 330px); + top: calc(50% + 6px); + bottom: auto; + width: min(44vw, 720px); + height: auto; + max-height: calc(100dvh - 228px); + object-fit: contain; + opacity: 0; + pointer-events: none; + filter: drop-shadow(0 28px 46px rgba(0, 0, 0, .48)); + transform: translate(0, -50%); + translate: calc(var(--object-fit-x, 0px) - 36px) 0; + transition: opacity .28s var(--ease), translate .28s var(--ease); +} + +.feature-object.is-visible { + opacity: .96; + translate: var(--object-fit-x, 0px) 0; + transform: translate(0, -50%) scale(1); +} + +.feature-object.is-right-edge { + right: 0; + bottom: auto; + top: 50%; + width: clamp(420px, 39vw, 720px); + max-height: none; + height: auto; + transform: translate(0, -50%) scale(.98); +} + +.feature-object.is-right-edge.is-visible { + transform: translate(0, -50%) scale(1); +} + +.feature-object.is-right-bottom { + right: 0; + left: auto; + bottom: 0; + top: auto; + width: clamp(440px, 44vw, 820px); + max-height: none; + height: auto; + transform: translateX(2%) scale(.98); +} + +.feature-object.is-right-bottom.is-visible { + transform: translateX(2%) scale(1); +} + +/* Coordinates are relative to the slide; anchors are relative to the image. */ +.feature-object.is-custom-layout { + left: var(--object-x, 100%); + top: var(--object-y, 100%); + right: auto; + bottom: auto; + width: var(--object-width, 44%); + height: var(--object-height, auto); + max-width: var(--object-max-width, none); + max-height: var(--object-max-height, none); + transform: translate(var(--object-anchor-x, -100%), var(--object-anchor-y, -100%)) scale(.98); + transform-origin: right bottom; +} + +.feature-object.is-custom-layout.is-visible { + transform: translate(var(--object-anchor-x, -100%), var(--object-anchor-y, -100%)); +} + +.feature-object-secondary { + filter: drop-shadow(0 28px 46px rgba(0, 0, 0, .34)); +} + +.mobile-certificate-gallery { + display: none; +} + +.feature-object.is-motion-bottom:not(.is-visible) { + translate: var(--object-fit-x, 0px) 36px; +} + +.feature-object.is-repositioning { + transition: none; +} + +.capabilities-workbench.is-certification-slide .feature-subtitle, +.capabilities-workbench.is-certification-slide [data-feature-description] { + display: none; +} + +@media (min-width: 861px) { + /* Reserve space for the title and toolbar instead of anchoring to viewport percentages. */ + .is-certification-slide .feature-object.is-custom-layout, + .is-certification-slide .feature-object.is-custom-layout.is-visible { + left: 35%; + top: var(--certificate-top, 240px); + width: 26%; + height: max(0px, calc(100% - var(--certificate-top, 240px) - 116px)); + max-height: none; + object-fit: contain; + transform: translate(-50%, 0); + } + + .is-certification-slide .feature-object-secondary.is-custom-layout, + .is-certification-slide .feature-object-secondary.is-custom-layout.is-visible { + left: 65%; + } +} + +.feature-table-wrap { + position: relative; + z-index: 2; + width: min(1320px, calc(100% - 220px)); + margin: auto; +} + +.feature-summary-table { + width: 100%; + border-collapse: collapse; + color: #20242b; + background: rgba(245, 247, 249, .82); + box-shadow: 0 24px 70px rgba(0, 0, 0, .22); + backdrop-filter: blur(5px); +} + +.feature-summary-table th { + height: 54px; + color: #fff; + background: rgba(36, 87, 171, .96); + font-size: 18px; + font-weight: 850; + text-align: center; +} + +.feature-summary-table th, +.feature-summary-table td { + border: 1px solid rgba(20, 27, 38, .38); +} + +.feature-summary-table td { + height: 48px; + padding: 0 22px; + font-size: 17px; + font-weight: 700; +} + +.feature-summary-table td:last-child { + width: 30%; + text-align: center; +} + +.capabilities-toolbar { + position: absolute; + z-index: 2; + left: clamp(24px, 5vw, 72px); + right: clamp(24px, 5vw, 72px); + bottom: 28px; + display: flex; + gap: 8px; + padding-top: 18px; + border-top: 1px solid rgba(255, 255, 255, .24); +} + +.capabilities-toolbar button { + min-width: 86px; + min-height: 40px; + padding: 0 16px; + border: 1px solid var(--line); + border-radius: 999px; + color: var(--muted); + background: rgba(255, 255, 255, .06); + cursor: pointer; +} + +.capabilities-toolbar button.is-active { + color: #031113; + background: var(--accent); + border-color: transparent; + font-weight: 800; +} + +.capabilities-toolbar .autoplay-toggle { + margin-left: auto; + color: var(--text); + background: rgba(255, 255, 255, .12); +} + +.autoplay-toggle, +.mobile-autoplay { + position: relative; + overflow: hidden; + display: inline-flex; + align-items: center; + justify-content: center; + gap: 7px; +} + +.autoplay-toggle img, +.mobile-autoplay img, +.autoplay-toggle span:not(.autoplay-progress), +.mobile-autoplay span:not(.autoplay-progress) { + position: relative; + z-index: 1; +} + +.autoplay-toggle img, +.mobile-autoplay img { + width: 18px; + height: 18px; + filter: invert(1); + opacity: .88; +} + +.autoplay-progress { + position: absolute; + z-index: 0; + inset: 0 auto 0 0; + width: 0%; + background: linear-gradient(90deg, rgba(158, 233, 255, .55), rgba(103, 240, 181, .24)); + opacity: .9; + pointer-events: none; +} + +.autoplay-toggle.is-running .autoplay-progress, +.mobile-autoplay.is-running .autoplay-progress { + animation: autoplay-fill var(--autoplay-duration, 9000ms) linear forwards; +} + +.autoplay-toggle.is-paused .autoplay-progress, +.mobile-autoplay.is-paused .autoplay-progress { + width: 0%; + animation: none; +} + +@keyframes autoplay-fill { + from { + width: 0%; + } + + to { + width: 100%; + } +} + +.mobile-slide-controls { + display: none; +} + +.mobile-slide-status { + display: none; +} + +.capabilities-workbench { + position: fixed; + inset: 0; + height: 100dvh; + overflow: hidden; + display: block; + background: var(--bg); +} + +.workbench-stage { + min-height: 0; + height: 100%; + position: relative; + top: 0; + display: flex; + align-items: center; + overflow: hidden; + padding: 108px clamp(24px, 5vw, 72px) 96px clamp(56px, 7vw, 132px); +} + +.project-dots { + position: absolute; + z-index: 6; + top: 50%; + right: clamp(26px, 4vw, 68px); + width: 50px; + padding: 12px 0; + transform: translateY(-50%); +} + +.project-progress { + display: grid; + gap: 3px; + justify-items: center; + padding: 13px 8px; + border: 1px solid rgba(255, 255, 255, .1); + border-radius: 999px; + background: rgba(6, 15, 18, .56); + box-shadow: 0 10px 30px rgba(0, 0, 0, .18), inset 0 1px rgba(255, 255, 255, .06); + backdrop-filter: blur(12px); + transition: border-color .2s var(--ease), background .2s var(--ease), box-shadow .2s var(--ease); +} + +.project-dots:hover:not(.is-closed-after-click) .project-progress, +.project-dots:focus-within:not(.is-closed-after-click) .project-progress { + border-color: rgba(255, 255, 255, .16); + background: rgba(6, 15, 18, .72); + box-shadow: 0 14px 36px rgba(0, 0, 0, .24), inset 0 1px rgba(255, 255, 255, .08); +} + +.project-menu { + position: absolute; + top: 50%; + right: -12px; + width: 360px; + max-height: min(680px, calc(100dvh - 220px)); + display: grid; + grid-template-rows: auto minmax(0, 1fr) auto; + padding: 10px 12px; + border: 1px solid rgba(255, 255, 255, .14); + border-radius: 8px; + background: rgba(5, 17, 19, .96); + backdrop-filter: blur(14px); + transform: translateY(-50%); + visibility: hidden; + pointer-events: none; + opacity: 0; + transition: opacity .2s var(--ease), visibility .2s; +} + +.project-dots:hover:not(.is-closed-after-click) .project-menu, +.project-dots:focus-within:not(.is-closed-after-click) .project-menu { + visibility: visible; + pointer-events: auto; + opacity: 1; +} + +.project-dots:hover:not(.is-closed-after-click) .project-progress, +.project-dots:focus-within:not(.is-closed-after-click) .project-progress { + visibility: hidden; +} + +.project-menu-list { + min-height: 0; + overflow-y: auto; + overscroll-behavior: contain; + scrollbar-width: thin; + display: grid; + gap: 8px; + padding: 8px 0; +} + +.project-preview { + position: relative; + display: flex; + align-items: flex-end; + justify-content: flex-end; + height: 96px; + min-height: 96px; + overflow: hidden; + padding: 12px 14px; + border: 1px solid rgba(255, 255, 255, .14); + border-radius: 4px; + background: #102025; + color: #fff; + text-align: right; + cursor: pointer; +} + +.project-preview::after { + content: ""; + position: absolute; + inset: 0; + background: linear-gradient(180deg, rgba(0, 0, 0, .12), rgba(0, 0, 0, .8)); + pointer-events: none; +} + +.project-preview:hover, +.project-preview.is-active { + border-color: var(--accent); +} + +.project-preview .project-title { + position: relative; + z-index: 1; + font-size: 13px; + font-weight: 700; + line-height: 1.5; + word-break: keep-all; + overflow-wrap: anywhere; + text-shadow: 0 1px 3px rgba(0, 0, 0, .8); +} + +.project-preview .thumbnail-background { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; +} + +.project-category-link { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; + min-height: 48px; + padding: 8px; + border: 0; + background: transparent; + color: rgba(255, 255, 255, .6); + cursor: pointer; + font-size: 12px; +} + +.project-category-link:first-child { + border-bottom: 1px solid rgba(255, 255, 255, .14); +} + +.project-category-link:last-child { + border-top: 1px solid rgba(255, 255, 255, .14); +} + +.project-category-link img { + width: 16px; + height: 16px; + filter: brightness(0) invert(1); +} + +.project-category-direction { + display: inline-flex; + align-items: center; + gap: 4px; + flex-shrink: 0; +} + +.project-category-link.is-next .project-category-direction { + flex-direction: row-reverse; +} + +.project-category-link strong { + font-size: 14px; + color: var(--accent); + text-transform: uppercase; +} + +.project-category-link:hover { + color: #fff; +} + +.dot-button { + position: relative; + z-index: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 0; + width: 32px; + min-width: 32px; + min-height: 17px; + padding: 0; + border: 0; + color: rgba(255, 255, 255, .52); + background: transparent; + cursor: pointer; +} + +.dot-mark { + width: 12px; + height: 2px; + display: block; + border-radius: 999px; + background: rgba(255, 255, 255, .32); + box-shadow: 0 0 0 1px rgba(0, 0, 0, .08); + transition: width .22s var(--ease), height .22s var(--ease), background .22s var(--ease), box-shadow .22s var(--ease); +} + +.dot-button:hover .dot-mark { + width: 20px; + background: rgba(255, 255, 255, .72); +} + +.dot-button.is-active .dot-mark { + width: 28px; + height: 3px; + background: #fff; + box-shadow: 0 0 12px rgba(158, 233, 255, .5); +} + +.capabilities-footer { + display: none; +} + +.capabilities-seo { + position: absolute; + width: 1px; + height: 1px; + overflow: hidden; + clip: rect(0 0 0 0); + clip-path: inset(50%); + white-space: normal; +} + +@media (prefers-reduced-motion: reduce) { + .feature-bg { + animation: none; + } + + .feature-object { + transition: none; + } +} + +code { + color: var(--accent-2); +} + +/* 회사소개 */ +.about-page { + background: #f3f4f3; + color: #07192d; +} + +.about-page .eyebrow { + color: #2aa6df; +} + +.about-hero, +.about-section { + width: min(1320px, calc(100% - 64px)); + margin: 0 auto; + padding: 104px 0; +} + +.about-hero { + min-height: auto; + display: grid; + grid-template-columns: minmax(0, .9fr) minmax(380px, 1.1fr); + gap: 44px; + align-items: center; + padding-top: 132px; + padding-bottom: 84px; +} + +.about-hero-copy h1, +.about-section h2 { + margin: 18px 0 26px; + color: #07192d; + font-size: clamp(38px, 5vw, 72px); + line-height: 1.06; +} + +.about-hero-copy > p, +.about-section > p { + max-width: 1100px; + color: #69717b; + font-size: clamp(18px, 2vw, 27px); + font-weight: 650; + line-height: 1.65; +} + +.capability-showcase { + margin-top: 42px; + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 16px; +} + +.capability-showcase article { + min-height: 360px; + position: relative; + display: flex; + flex-direction: column; + justify-content: flex-end; + overflow: hidden; + padding: 24px; + color: #fff; + border-radius: 8px; + isolation: isolate; +} + +.capability-showcase article::after { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + background: linear-gradient(180deg, rgba(7, 9, 13, .06), rgba(7, 9, 13, .88)); +} + +.capability-showcase img { + position: absolute; + inset: 0; + z-index: -2; + width: 100%; + height: 100%; + object-fit: cover; +} + +.capability-showcase span { + color: #9ee9ff; + font-size: 14px; + font-weight: 900; +} + +.capability-showcase strong { + display: block; + margin: 8px 0 4px; + font-size: 32px; + line-height: 1.1; +} + +.capability-showcase small { + color: #c6d0dc; + font-weight: 850; +} + +.timeline-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 34px 48px; + margin-top: 54px; + border-top: 4px solid #39ace2; +} + +.timeline-grid article { + padding-top: 28px; +} + +.timeline-grid span { + color: #2aa6df; + font-size: 42px; + font-weight: 950; +} + +.timeline-grid h3 { + margin: 12px 0 14px; + font-size: 24px; +} + +.timeline-grid p { + color: #738091; + font-size: 17px; + font-weight: 650; + line-height: 1.7; +} + +.org-chart { + margin-top: 54px; +} + +.ceo-node { + width: min(360px, 70vw); + margin: 0 auto 48px; + padding: 22px; + color: #fff; + background: #122569; + border-radius: 8px; + text-align: center; + font-size: 34px; + font-weight: 950; +} + +.org-columns { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 24px; + border-top: 2px solid #d7dce1; + padding-top: 40px; +} + +.org-columns article { + display: grid; + gap: 16px; +} + +.org-columns span { + color: #2aa6df; + font-size: 13px; + font-weight: 950; + text-transform: uppercase; +} + +.org-columns strong { + display: flex; + align-items: center; + justify-content: center; + min-height: 90px; + color: #fff; + background: #2697b4; + border-radius: 8px; + font-size: 27px; +} + +.org-columns article:nth-child(4) strong { + background: #627184; +} + +.org-columns p { + margin: 0; + padding: 18px; + color: #315068; + background: #eaf5fa; + border: 1px solid #b6dcec; + border-radius: 8px; + font-weight: 800; + line-height: 1.7; +} + +.partner-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 18px; + margin-top: 48px; +} + +.partner-grid span { + display: flex; + align-items: center; + justify-content: center; + min-height: 112px; + padding: 18px; + color: #1a4072; + background: #fff; + border-radius: 12px; + box-shadow: 0 12px 26px rgba(10, 24, 36, .14); + font-size: 24px; + font-weight: 950; + text-align: center; +} + +/* 문의하기 */ +.contact-page { + width: min(var(--max), calc(100% - 48px)); + margin: 0 auto; + padding: 136px 0 90px; +} + +.contact-hero { + max-width: 840px; + margin-bottom: 58px; +} + +.contact-layout { + display: grid; + grid-template-columns: minmax(0, .92fr) minmax(0, 1.08fr); + gap: 24px; +} + +.office-list { + display: grid; + gap: 12px; +} + +.office-list article, +.contact-form { + padding: 28px; + background: var(--panel-solid); + border: 1px solid var(--line); +} + +.office-list h2 { + margin-bottom: 10px; +} + +.office-list p { + margin-bottom: 0; + color: var(--muted); + line-height: 1.7; +} + +.contact-form { + display: grid; + gap: 18px; +} + +.contact-form label { + display: grid; + gap: 8px; +} + +.contact-form label span { + color: var(--muted); + font-size: 13px; + font-weight: 750; +} + +.contact-form input, +.contact-form select, +.contact-form textarea { + width: 100%; + color: var(--text); + background: rgba(255, 255, 255, .055); + border: 1px solid var(--line); + border-radius: 6px; + padding: 13px 14px; + outline: none; +} + +.contact-form select { + padding-right: 42px; + -webkit-appearance: none; + appearance: none; + background-image: url("../assets/icons/keyboard_arrow_down.svg"); + background-repeat: no-repeat; + background-position: right 12px center; + background-size: 20px; + cursor: pointer; +} + +.contact-form textarea { + resize: vertical; +} + +.contact-form input:focus, +.contact-form select:focus, +.contact-form textarea:focus { + border-color: var(--accent); +} + +.form-note { + margin: 0; + color: var(--dim); + font-size: 13px; + line-height: 1.6; +} + +.form-note.is-success { + color: #78d7a5; +} + +.form-note.is-error { + color: #ff9a96; +} + +body.is-contact-submitting { + overflow: hidden; +} + +.contact-submit-overlay[hidden] { + display: none; +} + +.contact-submit-overlay { + position: fixed; + z-index: 100; + inset: 0; + display: grid; + place-items: center; + padding: 24px; + background: rgba(4, 7, 10, .78); + backdrop-filter: blur(10px); + outline: none; +} + +.contact-submit-status { + width: min(360px, 100%); + padding: 24px; + border: 1px solid rgba(255, 255, 255, .12); + border-radius: 6px; + background: rgba(10, 18, 24, .96); + box-shadow: 0 20px 56px rgba(0, 0, 0, .34); +} + +.contact-submit-status strong { + display: block; + margin-bottom: 18px; + font-size: 16px; +} + +.contact-progress { + height: 4px; + overflow: hidden; + border-radius: 999px; + background: rgba(255, 255, 255, .12); +} + +.contact-progress span { + display: block; + width: 0; + height: 100%; + border-radius: inherit; + background: var(--accent); + box-shadow: 0 0 14px rgba(158, 233, 255, .46); + transition: width .16s linear; +} + +.contact-submit-status > span { + display: block; + margin-top: 10px; + color: var(--muted); + font-size: 12px; + font-variant-numeric: tabular-nums; + text-align: right; +} + +.contact-body .contact-page { + display: grid; + grid-template-columns: minmax(260px, .8fr) minmax(0, 1.2fr); + grid-template-rows: auto auto; + gap: 24px 56px; + align-content: center; + min-height: calc(100dvh - 152px); + padding: 96px 0 24px; +} + +.contact-body .contact-hero { + margin: 0; + grid-column: 1; + grid-row: 1; +} + +.contact-body .contact-hero h1 { + margin: 12px 0 18px; + font-size: 42px; +} + +.contact-body .contact-hero p { + font-size: 15px; +} + +.contact-body .contact-layout { + display: contents; +} + +.contact-body .office-list { + grid-column: 1; + grid-row: 2; + align-content: start; + gap: 18px; +} + +.contact-body .office-list article { + padding: 16px 0 0; + border: 0; + border-top: 1px solid var(--line); + background: transparent; +} + +.contact-body .office-list span { + margin-bottom: 6px; + letter-spacing: 0; +} + +.contact-body .office-list h2 { + margin: 0 0 6px; + font-size: 18px; +} + +.contact-body .office-list p { + margin: 0; + font-size: 14px; +} + +.contact-body .contact-form { + grid-column: 2; + grid-row: 1 / span 2; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px 16px; + align-content: end; + padding: 0; + border: 0; + background: transparent; + min-width: 0; +} + +.contact-body .contact-form label { + min-width: 0; + gap: 6px; +} + +.contact-body .form-wide { + grid-column: 1 / -1; +} + +.contact-body .contact-form input, +.contact-body .contact-form select, +.contact-body .contact-form textarea { + padding: 10px 12px; + font-size: 14px; +} + +.contact-body .contact-form select option { + color: var(--text); + background: var(--panel-solid); +} + +.contact-body .contact-form textarea { + min-height: 100px; + max-height: 200px; +} + +.contact-body .contact-form input[type="file"] { + font-size: 12px; +} + +.contact-body .consent-row { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 8px 14px; +} + +.contact-body .contact-form .consent-label { + display: flex; + align-items: flex-start; + gap: 8px; + cursor: pointer; +} + +.contact-body .contact-form input[type="checkbox"] { + flex: 0 0 16px; + width: 16px; + height: 16px; + margin: 2px 0 0; + accent-color: var(--accent); +} + +.contact-body .consent-label span { + font-size: 12px; + line-height: 1.6; +} + +/* 공통: 개인정보 처리방침과 사이트맵 모달 */ +.privacy-link { + color: var(--muted); + border: 0; + padding: 0; + background: none; + cursor: pointer; + font-size: 12px; + text-decoration: underline; + text-underline-offset: 3px; +} + +.footer-links button { + padding: 0; + border: 0; + background: none; + color: var(--muted); + cursor: pointer; +} + +.footer-links button:hover, +.privacy-link:hover { + color: var(--text); +} + +html.has-site-dialog, +.has-site-dialog body { + overflow: hidden; +} + +.site-dialog { + width: min(720px, calc(100% - 32px)); + max-height: calc(100dvh - 48px); + padding: 0; + border: 1px solid var(--line-strong); + border-radius: 8px; + color: var(--text); + background: #101419; + box-shadow: 0 24px 80px rgba(0, 0, 0, .5); + overflow: hidden; +} + +.site-dialog[open] { + display: flex; + flex-direction: column; +} + +.site-dialog::backdrop { + background: rgba(0, 0, 0, .7); +} + +.site-dialog-header { + display: flex; + flex: 0 0 auto; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 18px 24px; + border-bottom: 1px solid var(--line); +} + +.site-dialog-header h2 { + margin: 0; + font-size: 22px; +} + +.dialog-close { + flex: 0 0 36px; + width: 36px; + height: 36px; + padding: 0; + border: 0; + border-radius: 4px; + background: rgba(255, 255, 255, .06); + font-size: 26px; + cursor: pointer; +} + +.site-dialog-content { + min-height: 0; + padding: 24px; + overflow-y: auto; + overscroll-behavior: contain; + font-size: 14px; + line-height: 1.8; +} + +.site-dialog-content h3 { + margin: 24px 0 8px; + font-size: 16px; +} + +.site-dialog-content p { + margin: 0 0 16px; + color: var(--muted); +} + +.site-dialog-content a { + color: var(--accent-2); +} + +.site-dialog-content .policy-intro { + padding-bottom: 16px; + border-bottom: 1px solid var(--line); + font-size: 12px; +} + +.sitemap-groups { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 24px; +} + +.sitemap-groups section { + display: grid; + align-content: start; + gap: 6px; +} + +.sitemap-groups h3 { + margin: 0 0 8px; +} + +.sitemap-groups a:hover { + text-decoration: underline; +} + +@media (max-width: 480px) { + .sitemap-groups { + grid-template-columns: minmax(0, 1fr); + } + + .site-dialog-header, + .site-dialog-content { + padding: 16px; + } +} + +.contact-body button:disabled { + opacity: .4; + cursor: not-allowed; + transform: none; +} + +@media (max-width: 860px) { + .contact-body .contact-page { + grid-template-columns: minmax(0, 1fr); + gap: 28px; + min-height: 0; + padding: 100px 0 36px; + } + + .contact-body .contact-form { + grid-column: 1; + grid-row: 2; + } + + .contact-body .office-list { + grid-row: 3; + } +} + +@media (max-width: 480px) { + .contact-body .contact-form { + grid-template-columns: minmax(0, 1fr); + } +} + +/* 공통: 푸터 */ +.site-footer { + display: flex; + flex-wrap: wrap; + align-items: flex-start; + justify-content: space-between; + gap: 24px; + padding: 28px clamp(24px, 4vw, 54px) 42px; + color: var(--dim); + border-top: 1px solid var(--line); +} + +.site-footer div { + display: grid; + gap: 6px; +} + +.site-footer strong { + color: var(--text); + letter-spacing: 0; + font-size: 14px; +} + +.footer-links { + display: flex; + flex-wrap: wrap; + gap: 12px 24px; +} + +.footer-copyright { + margin-top: 10px; + font-size: 12px; + line-height: 1.6; +} + +.site-footer a { + color: var(--muted); +} + +@keyframes slow-zoom { + to { + transform: scale(1.08); + } +} + +/* 공통 및 각 페이지의 반응형 설정 */ +@media (max-width: 1080px) { + + .org-columns, + .partner-grid { + grid-template-columns: repeat(2, 1fr); + } + + .timeline-grid { + grid-template-columns: 1fr 1fr; + } +} + +@media (max-width: 860px) { + body.capabilities-body { + overflow: auto; + } + + .page-dots { + display: none; + } + + .desktop-nav { + display: none; + } + + .nav-toggle { + display: inline-flex; + } + + .hero-grid, + .contact-layout, + .intro { + grid-template-columns: 1fr; + } + + .hero-grid { + width: min(100% - 36px, var(--max)); + padding-bottom: 118px; + } + + .hero-panel { + grid-template-columns: repeat(3, 1fr); + } + + .hero-panel div { + padding: 16px; + } + + .hero-panel strong { + font-size: 21px; + } + + .proof-strip { + grid-column: auto; + grid-template-columns: 1fr; + } + + .showcase-preview { + grid-template-columns: 1fr; + } + + .preview-card, + .showcase-preview { + min-height: 480px; + } + + .about-hero, + .about-section { + width: calc(100% - 36px); + padding: 76px 0; + } + + .about-hero { + grid-template-columns: 1fr; + padding-top: 118px; + } + + .timeline-grid, + .org-columns, + .partner-grid, + .capability-showcase { + grid-template-columns: 1fr; + } + + .capabilities-workbench { + position: relative; + inset: auto; + display: block; + height: auto; + min-height: 100svh; + overflow: hidden; + padding-bottom: 116px; + } + + .workbench-stage { + position: relative; + height: auto; + min-height: 100svh; + padding: 112px 24px 144px; + } + + .feature-content { + position: relative; + top: auto; + left: auto; + width: 100%; + max-height: none; + overflow: visible; + } + + .feature-object { + display: none; + } + + .project-dots { + display: none; + } + + .capabilities-toolbar .autoplay-toggle { + display: none; + } + + .dot-button { + min-width: 28px; + } + + .dot-mark { + width: 22px; + } + + .mobile-slide-controls { + position: fixed; + z-index: 8; + left: 50%; + right: auto; + bottom: max(14px, env(safe-area-inset-bottom)); + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + width: min(520px, calc(100% - 32px)); + margin: 0; + padding: 12px; + border: 1px solid rgba(255, 255, 255, .14); + background: rgba(5, 11, 13, .78); + backdrop-filter: blur(18px); + transform: translateX(-50%); + } + + .mobile-slide-controls button { + min-height: 54px; + border: 0; + border-radius: 6px; + color: #061113; + background: rgba(245, 247, 239, .9); + font-size: 20px; + font-weight: 850; + cursor: pointer; + } + + .mobile-slide-controls .mobile-autoplay { + color: var(--text); + background: rgba(255, 255, 255, .14); + } + + .mobile-slide-controls span { + display: flex; + align-items: center; + justify-content: center; + min-height: 54px; + color: rgba(255, 255, 255, .72); + font-size: 14px; + font-weight: 800; + letter-spacing: .12em; + } +} + +@media (max-width: 560px) { + .site-header { + height: 64px; + padding: 0 16px; + } + + .mobile-menu { + top: 64px; + } + + .brand { + font-size: 12px; + } + + .brand-logo { + width: 112px; + } + + .hero-grid { + padding-top: 110px; + } + + .hero-copy h1, + .feature-content h1, + .contact-hero h1 { + font-size: clamp(36px, 13vw, 54px); + } + + .hero-panel { + grid-template-columns: 1fr; + } + + .hero-footer { + display: none; + } + + .section, + .contact-page { + width: calc(100% - 32px); + } + + .section { + padding: 78px 0; + } + + .capabilities-toolbar { + overflow-x: auto; + left: 24px; + right: 24px; + } + + .site-footer { + display: grid; + padding-left: 16px; + padding-right: 16px; + } + + .about-hero, + .about-section { + width: calc(100% - 28px); + } + + .about-hero h1, + .about-section h2 { + font-size: clamp(34px, 12vw, 48px); + } + + .partner-grid span { + min-height: 86px; + font-size: 18px; + } +} + +/* 회사소개: 현재 레이아웃과 반응형 설정 */ +.about-refresh { + background: #f7f9fa; + color: #18262e; +} + +.about-refresh > section { + width: 100%; + padding: 64px max(28px, calc((100% - 1200px) / 2)); + border-bottom: 1px solid #dce3e7; +} + +.about-refresh .about-hero { + grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); + gap: 64px; + padding-top: 112px; + background: #0c1014; + color: var(--text); +} + +.about-refresh .overview-logo { + display: block; + width: min(340px, 100%); + height: auto; + margin: 30px 0; + border-radius: 4px; +} + +.about-refresh .about-hero h1 { + margin: 0 0 24px; + font-size: 38px; + line-height: 1.25; + color: var(--text); +} + +.about-refresh .about-hero-copy > p { + font-size: 16px; + font-weight: 400; + line-height: 1.85; + color: var(--muted); +} + +.about-refresh .about-hero-copy > .eyebrow { + color: var(--accent); +} + +.about-refresh .eyebrow { + font-size: 12px; + letter-spacing: 0; + color: #1788af; +} + +.overview-facts dl { + margin: 0; +} + +.overview-facts dl > div { + display: grid; + grid-template-columns: 90px minmax(0, 1fr); + gap: 20px; + padding: 18px 0; + border-bottom: 1px solid var(--line); + font-size: 14px; + line-height: 1.7; +} + +.overview-facts dt { + color: var(--muted); +} + +.overview-facts dd { + margin: 0; +} + +.about-refresh .about-section h2 { + margin: 12px 0 28px; + font-size: 32px; + line-height: 1.3; +} + +.about-refresh .capability-showcase { + margin-top: 0; +} + +.company-profile-actions { + display: flex; + justify-content: flex-end; + margin-top: 20px; +} + +.about-refresh .capability-showcase article { + min-height: 0; + height: 320px; +} + +.about-refresh .capability-showcase strong { + font-size: 26px; +} + +.about-refresh .timeline-grid { + margin-top: 24px; + gap: 24px 32px; + border-top-width: 2px; +} + +.about-refresh .timeline-grid article { + padding-top: 16px; +} + +.about-refresh .timeline-grid span { + font-size: 30px; +} + +.about-refresh .timeline-grid h3 { + font-size: 18px; + line-height: 1.4; + margin: 10px 0; +} + +.about-refresh .timeline-grid p { + font-size: 14px; + font-weight: 400; + margin: 0; +} + +.timeline-events { + display: grid; + gap: 7px; + list-style: none; + padding: 0; + margin: 0; + color: #738091; + font-size: 14px; + line-height: 1.7; +} + +.about-refresh .org-chart { + margin-top: 24px; +} + +.about-refresh .ceo-node { + position: relative; + width: 200px; + padding: 16px; + margin-bottom: 32px; + border-radius: 4px; + font-size: 22px; + background: #243d4a; +} + +.about-refresh .ceo-node::after { + content: ""; + position: absolute; + width: 1px; + height: 32px; + top: 100%; + left: 50%; + background: #ccd8df; +} + +.about-refresh .org-columns { + gap: 20px; + padding-top: 24px; + align-items: start; + border-top: 1px solid #ccd8df; +} + +.about-refresh .org-columns article { + grid-template-rows: 32px 64px auto; + gap: 12px; + position: relative; +} + +.about-refresh .org-columns article::before { + content: ""; + position: absolute; + top: -24px; + left: 50%; + height: 24px; + width: 1px; + background: #ccd8df; +} + +.about-refresh .org-columns span { + font-size: 10px; + line-height: 1.5; + text-align: center; + color: #637580; + align-self: center; +} + +.about-refresh .org-columns strong { + min-height: 0; + font-size: 20px; + border-radius: 4px; + background: #258ba4; +} + +.org-teams { + display: grid; + gap: 8px; + margin: 0; + padding: 0 0 0 16px; + list-style: none; + border-left: 1px solid #ccd8df; +} + +.org-teams li { + position: relative; + padding: 10px 12px; + font-size: 14px; + background: #edf3f6; + border: 1px solid #dce6ec; + border-radius: 4px; +} + +.org-teams li::before { + content: ""; + position: absolute; + left: -17px; + top: 50%; + width: 16px; + height: 1px; + background: #ccd8df; +} + +.about-refresh .partner-grid { + grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 16px; + margin-top: 24px; +} + +.partner-grid figure { + margin: 0; + height: 104px; + /* padding: 16px; */ + background: #fff; + border: 1px solid #dfe7eb; + border-radius: 4px; +} + +.partner-grid img { + width: 100%; + height: 100%; + object-fit: contain; +} + +@media (min-width: 861px) and (min-height: 700px) { + .about-refresh > section { + min-height: calc(100dvh - 72px); + display: flex; + flex-direction: column; + justify-content: center; + } + + .about-refresh .about-hero { + display: grid; + min-height: 100dvh; + } +} + +@media (max-width: 1000px) { + .about-refresh .about-hero { + gap: 32px; + } + + .about-refresh .org-columns { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } +} + +@media (max-width: 860px) { + .about-refresh .about-hero { + grid-template-columns: minmax(0, 1fr); + } + + .about-refresh .about-section h2, + .about-refresh .about-hero h1 { + font-size: 28px; + } + + .about-refresh .capability-showcase, + .about-refresh .timeline-grid, + .about-refresh .partner-grid { + grid-template-columns: repeat(2, minmax(0, 1fr)); + } + + .about-refresh .ceo-node::after, + .about-refresh .org-columns article::before { + display: none; + } +} + +@media (max-width: 540px) { + .about-refresh .org-columns, + .about-refresh .timeline-grid { + grid-template-columns: minmax(0, 1fr); + } + + .about-refresh .capability-showcase article { + height: 240px; + padding: 16px; + } + + .about-refresh .capability-showcase small { + font-size: 10px; + overflow-wrap: anywhere; + } +} + +/* 공통: 카테고리 표기와 한글 줄바꿈 */ +.eyebrow, +.section-label, +.about-page .eyebrow, +.about-refresh .eyebrow, +.about-refresh .about-hero-copy > .eyebrow, +.about-refresh .about-hero-copy > p.eyebrow, +.feature-content p.eyebrow, +.contact-body .contact-hero p.eyebrow { + margin: 0; + max-width: none; + color: var(--accent-2); + font-size: 14px; + font-weight: 800; + line-height: 1.5; + letter-spacing: 0; + text-transform: uppercase; +} + +.about-refresh .about-section > .eyebrow { + color: #147d68; +} + +h1, h2, h3, p, a, button, label, span, strong, small, dt, dd, li, td, th { + word-break: keep-all; + overflow-wrap: break-word; +} + +.home-body .preview-card strong, +.about-refresh .capability-showcase small { + overflow-wrap: break-word; +} + +/* 기술 역량: 모바일 */ +@media (max-width: 860px) { + body.capabilities-body { + overflow: hidden; + } + + .capabilities-body .capabilities-workbench { + position: fixed; + inset: 72px 0 0; + height: calc(100dvh - 72px); + min-height: 0; + padding: 0; + display: grid; + grid-template-rows: minmax(0, 1fr) auto; + } + + .capabilities-body .workbench-stage { + display: grid; + grid-template-rows: auto minmax(0, 1fr); + height: 100%; + min-height: 0; + min-width: 0; + padding: 0; + overflow: hidden; + } + + .capabilities-body .feature-content { + grid-row: 2; + align-self: stretch; + min-height: 0; + max-height: none; + width: 100%; + padding: 24px 20px 84px; + overflow-y: auto; + overscroll-behavior: contain; + -webkit-overflow-scrolling: touch; + } + + .capabilities-body .feature-content h1 { + font-size: 28px; + line-height: 1.3; + } + + .capabilities-body .feature-subtitle { + margin-bottom: 24px; + font-size: 14px; + } + + .capabilities-body .feature-table-wrap { + grid-row: 2; + min-height: 0; + min-width: 0; + width: 100%; + margin: 0; + padding: 24px 16px 84px; + overflow-x: hidden; + overflow-y: auto; + overscroll-behavior: contain; + align-self: stretch; + } + + .capabilities-body .feature-summary-table { + min-width: 0; + table-layout: fixed; + } + + .capabilities-body .feature-summary-table th, + .capabilities-body .feature-summary-table td { + padding: 12px 8px; + font-size: 12px; + line-height: 1.6; + overflow-wrap: anywhere; + } + + .capabilities-body .feature-summary-table th { + height: 44px; + } + + .capabilities-body .feature-summary-table td { + height: auto; + } + + .capabilities-body .feature-summary-table th:first-child, + .capabilities-body .feature-summary-table td:first-child { + width: 65%; + } + + .capabilities-body .feature-summary-table th:last-child, + .capabilities-body .feature-summary-table td:last-child { + width: 35%; + } + + .capabilities-body .capabilities-toolbar { + position: relative; + grid-row: 1; + inset: auto; + display: grid; + grid-template-columns: repeat(5, minmax(0, 1fr)); + gap: 4px; + padding: 10px 12px; + background: #101419; + overflow: visible; + } + + .capabilities-body .capabilities-toolbar button { + min-width: 0; + min-height: 36px; + padding: 0 4px; + font-size: 10px; + border-radius: 4px; + } + + .capabilities-body .capabilities-toolbar .autoplay-toggle { + display: none; + } + + .capabilities-body .feature-object.is-custom-layout, + .capabilities-body .feature-object-secondary.is-custom-layout { + left: 50%; + top: auto; + bottom: 24px; + width: 42%; + height: auto; + max-height: 48%; + transform: translate(-100%, 0) scale(.98); + } + + .capabilities-body .feature-object-secondary.is-custom-layout { + left: calc(50% + 12px); + transform: translate(0, 0) scale(.98); + } + + .capabilities-body .feature-object.is-custom-layout.is-visible, + .capabilities-body .feature-object-secondary.is-custom-layout.is-visible { + transform: translate(-100%, 0); + } + + .capabilities-body .feature-object-secondary.is-custom-layout.is-visible { + transform: translate(0, 0); + } + + .capabilities-body .mobile-certificate-gallery:not([hidden]) { + display: grid; + gap: 24px; + margin-top: 24px; + } + + .mobile-certificate-gallery img { + display: block; + width: 100%; + height: auto; + } + + .capabilities-body .mobile-slide-controls { + position: relative; + inset: auto; + width: 100%; + transform: none; + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 8px; + padding: 8px 12px max(10px, env(safe-area-inset-bottom)); + border: 0; + border-top: 1px solid var(--line); + background: #101419; + backdrop-filter: none; + } + + .capabilities-body .mobile-slide-controls button { + min-width: 0; + min-height: 40px; + font-size: 14px; + border-radius: 4px; + } + + .capabilities-body .mobile-slide-controls span { + min-height: 0; + font-size: 12px; + letter-spacing: 0; + } + + .capabilities-body .mobile-slide-controls .autoplay-progress { + display: block; + } + + .capabilities-body .mobile-slide-status { + display: block; + position: absolute; + right: 16px; + bottom: calc(74px + env(safe-area-inset-bottom, 0px)); + z-index: 7; + } + + .mobile-slide-status .mobile-autoplay { + width: 104px; + height: 40px; + padding: 0 10px; + border: 1px solid var(--line-strong); + border-radius: 6px; + color: var(--text); + background: rgba(12, 18, 22, .92); + box-shadow: 0 3px 12px rgba(0, 0, 0, .25); + cursor: pointer; + } + + .mobile-slide-status [data-slide-counter] { + font-size: 12px; + font-weight: 750; + font-variant-numeric: tabular-nums; + white-space: nowrap; + } +} + +@media (max-width: 560px) { + .capabilities-body .capabilities-workbench { + top: 64px; + height: calc(100dvh - 64px); + } +} + +/* ESG */ +.esg-hero { + position: relative; + min-height: 100dvh; + display: flex; + align-items: center; + padding: 112px max(28px, calc((100% - 1200px) / 2)) 96px; + isolation: isolate; +} + +.esg-hero-image { + position: absolute; + inset: 0; + width: 100%; + height: 100%; + object-fit: cover; + z-index: -2; +} + +.esg-hero::after { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + background: linear-gradient(90deg, rgba(5, 16, 12, .82), rgba(5, 16, 12, .12)); +} + +.esg-hero-copy { + max-width: 660px; +} + +.esg-hero h1 { + font-size: 80px; + line-height: 1.1; + margin: 20px 0 24px; +} + +.esg-hero-copy > p:not(.eyebrow) { + font-size: 18px; + line-height: 1.85; + color: #e1eae4; + margin-bottom: 28px; +} + +.esg-workspace { + display: grid; + grid-template-columns: minmax(240px, .75fr) minmax(0, 1.6fr); + gap: 40px; + height: calc(100dvh - 72px); + min-height: 580px; + padding: 40px max(28px, calc((100% - 1200px) / 2)); + background: #0c1014; + scroll-margin-top: 72px; +} + +.esg-policy-tabs { + display: grid; + grid-template-rows: repeat(3, minmax(0, 1fr)); + gap: 12px; + min-height: 0; +} + +.esg-policy-tab { + position: relative; + isolation: isolate; + overflow: hidden; + min-width: 0; + padding: 24px; + border: 1px solid rgba(255, 255, 255, .16); + border-radius: 4px; + color: white; + text-align: left; + cursor: pointer; + background: #17211e; +} + +.esg-policy-tab img { + position: absolute; + inset: 0; + z-index: -2; + width: 100%; + height: 100%; + object-fit: cover; + object-position: 70% center; + transition: transform .3s var(--ease); +} + +.esg-policy-tab::after { + content: ""; + position: absolute; + inset: 0; + z-index: -1; + background: linear-gradient(90deg, rgba(6, 13, 12, .85), rgba(6, 13, 12, .12)); +} + +.esg-policy-tab span { + display: grid; + gap: 10px; +} + +.esg-policy-tab small { + font-size: 11px; + color: #d9e9df; +} + +.esg-policy-tab strong { + font-size: 24px; +} + +.esg-policy-tab[aria-selected="true"] { + border-color: var(--accent-2); + box-shadow: inset 4px 0 var(--accent-2); +} + +.esg-policy-tab:hover img { + transform: scale(1.03); +} + +.esg-policy-tab:focus-visible, +.esg-policy-panel:focus-visible { + outline: 2px solid var(--accent-2); + outline-offset: 3px; +} + +.esg-policy-reader { + min-height: 0; + min-width: 0; +} + +.esg-policy-panel { + height: 100%; + overflow-y: auto; + overscroll-behavior-y: auto; + padding: 0 24px 24px 0; + scrollbar-width: thin; + scroll-margin-top: 72px; +} + +.esg-policy-heading { + padding: 0 0 24px; + border-bottom: 1px solid var(--line); + margin-bottom: 24px; +} + +.esg-policy-heading h2 { + margin: 10px 0 0; + font-size: 32px; +} + +.esg-policy-text { + font-size: 15px; + line-height: 1.85; + color: #bfc8cc; +} + +.esg-policy-text h3 { + margin: 28px 0 10px; + font-size: 17px; + color: var(--text); + line-height: 1.6; +} + +.esg-policy-text p { + margin: 0 0 16px; +} + +.esg-policy-text ul { + padding-left: 20px; + margin: 10px 0 24px; +} + +.esg-policy-text li { + margin-bottom: 6px; +} + +.esg-table-scroll { + overflow-x: auto; + margin: 20px 0; +} + +.esg-policy-text table { + border-collapse: collapse; + width: 100%; + min-width: 420px; + font-size: 13px; +} + +.esg-policy-text th, +.esg-policy-text td { + padding: 10px 12px; + border: 1px solid var(--line); + text-align: left; +} + +.esg-policy-text th { + background: #19252a; + color: var(--text); +} + +.esg-directions dl > div { + padding: 16px 0; + border-bottom: 1px solid var(--line); +} + +.esg-directions dt { + color: var(--accent-2); + font-weight: 750; +} + +.esg-directions dd { + margin: 6px 0 0; +} + +@media (max-width: 860px) { + .esg-hero h1 { + font-size: 60px; + } + + .esg-hero-copy > p:not(.eyebrow) { + font-size: 16px; + } + + .esg-workspace { + grid-template-columns: minmax(0, 1fr); + grid-template-rows: 104px minmax(0, 1fr); + gap: 24px; + padding: 24px 20px; + } + + .esg-policy-tabs { + grid-template-columns: repeat(3, minmax(0, 1fr)); + grid-template-rows: minmax(0, 1fr); + gap: 8px; + } + + .esg-policy-tab { + padding: 12px; + text-align: center; + } + + .esg-policy-tab small { + display: none; + } + + .esg-policy-tab strong { + font-size: 16px; + } + + .esg-policy-panel { + padding-right: 10px; + } + + .esg-policy-heading h2 { + font-size: 26px; + } +} + +@media (max-width: 560px) { + .esg-workspace { + height: calc(100dvh - 64px); + min-height: 480px; + scroll-margin-top: 64px; + } +} + +@media (min-width: 861px) and (min-height: 700px) { + .esg-workspace { + min-height: 0; + height: calc(100dvh - 72px); + padding-top: 28px; + padding-bottom: 28px; + } +} + +/* 회사소개: 연혁 */ +.about-refresh .chronology-grid { + border-top: 0; + margin-top: 0; + gap: 24px 32px; + align-content: start; +} + +.about-refresh .chronology-grid article { + position: relative; + border-top: 1px solid #68b4c4; + padding-top: 12px; +} + +.chronology-grid article::before { + content: ""; + position: absolute; + width: 7px; + height: 7px; + top: -4px; + left: 0; + background: #258ba4; +} + +.about-refresh .chronology-grid h3 { + font-size: 17px; + margin: 8px 0 10px; +} + +.chronology-grid .timeline-events { + font-size: 13px; + line-height: 1.5; + gap: 4px; +} + +@media (min-width: 861px) and (min-height: 700px) { + .about-refresh .timeline { + min-height: calc(100dvh - 72px); + padding-top: 32px; + padding-bottom: 32px; + } + + .about-refresh .timeline > h2 { + margin: 8px 0 24px; + font-size: 28px; + } + + .about-refresh .chronology-grid { + grid-template-columns: repeat(3, minmax(0, 1fr)); + } +} diff --git a/esg.html b/esg.html new file mode 100644 index 0000000..282ff19 --- /dev/null +++ b/esg.html @@ -0,0 +1,341 @@ + + + + + + + ESG · MOBIPINTECH + + + + + + + + + + +
+
+ +
+

Environment · Social · Governance

+

ESG

+

환경을 생각하는 기술, 사람을 존중하는 일터.
안전과 신뢰를 바탕으로 지속 가능한 성장을 만들어갑니다.

+ 경영 원칙 보기 +
+
+
+
+ + + +
+
+
+

Safety & Health

안전보건

+
+

모비핀테크놀러지㈜는 “안전하고 건강한 근무환경 조성을 통해 임직원의 삶의 질 향상과 지속 가능한 성장을 실현한다”는 안전보건 경영방침 아래 다음 사항을 적극 실천한다.

+

Ⅰ. 안전보건 경영 실천

+

모든 경영활동에서 안전과 보건을 최우선 가치로 고려하며, 임직원과 협력사가 안전하고 건강하게 근무할 수 있는 환경을 조성한다.

+

Ⅱ. 안전보건 관리체계 구축 및 이행

+

산업안전보건법 및 관계 법령을 준수하고, 사업 특성에 적합한 안전보건 관리체계를 구축·운영하여 관련 책임과 의무를 성실히 이행한다.

+

Ⅲ. 안전문화 정착 및 참여 확대

+

임직원 및 이해관계자에게 필요한 안전보건 정보를 투명하게 제공하고, 자율적인 참여와 실천을 통해 안전문화를 조직 내에 정착시킨다.

+

Ⅳ. 사고 예방 중심의 안전활동 강화

+

사무환경 및 프로젝트 수행 과정에서 발생 가능한 위험요인을 사전에 발굴·개선하며, 예방 중심의 안전활동을 지속 강화한다.

+

Ⅴ. 협력사 및 고객사 안전관리 준수

+

협력사 및 고객사와의 업무 수행 시 안전보건 기준을 준수하며, 안전한 작업환경 조성을 위해 상호 협력한다.

+

2026년 5월 11일
모비핀테크놀러지㈜ 대표이사 권오규

+

안전보건관리 추진체계

+

비전 :

+

모비핀테크놀러지㈜는 모든 경영활동에서 안전보건을 최우선으로 하여 안전하고 건강한 근무환경을 조성하고 지속 가능한 기업문화를 구축한다.

+

목표 및 중점 추진과제

+

1. 안전보건 관리체계 구축 및 운영

+

중점 추진과제 :

+
    +
  • 안전보건관리체계 지속 개선
  • +
  • 사업장 위험성평가 실시 및 관리
  • +
  • 안전보건관리 규정 운영 강화
  • +
  • 고객사 및 협력사 안전요구사항 준수
  • +
  • 정기 안전점검 및 개선활동 수행
  • +
  • 산업재해 예방활동 강화
  • +
+

2. 안전문화 정착 및 교육 강화

+

중점 추진과제 :

+
    +
  • 안전보건 공지 및 교육 운영 활성화
  • +
  • 신규입사자 안전보건교육 실시
  • +
  • 정기 안전보건교육 실시
  • +
  • 비상대응체계 및 대응훈련 운영
  • +
  • 임직원 건강관리 및 근골격계 예방활동 강화
  • +
+

3. 선제적 사고예방 활동 강화

+

중점 추진과제 :

+
    +
  • 사무환경 위험요인 점검 및 개선
  • +
  • 고객사 상주 및 현장업무 안전관리 강화
  • +
  • 장시간 근로 및 과로 예방활동 실시
  • +
  • 전기·화재·정보보안 관련 위험 예방활동 강화
  • +
  • 사고 발생 시 재발방지 대책 수립 및 이행
  • +
+

4. 2026년 안전보건 관리 목표 설정

+
구분목표비고
산업재해 발생건수0건
중대재해 발생건수0건
안전보건 교육 이수율100%
정기 위험성 평가 실시율100%
안전점검 실시 횟수분기 1회 이상
+

역할 및 책임

+

안전보건관리책임자 (안전보건 업무 총괄) :

+
    +
  • 안전보건 경영활동 총괄 관리
  • +
  • 안전보건 계획 수립 및 운영
  • +
  • 위험성평가 총괄 관리
  • +
  • 산업재해 예방 및 개선활동 추진
  • +
  • 관리감독자 지도 및 감독
  • +
+

안전보건담당자 (안전보건 실무 운영) :

+
    +
  • 안전보건 교육 운영
  • +
  • 위험요인 점검 및 개선관리
  • +
  • 안전보건 관련 문서 및 법규 관리
  • +
  • 비상대응체계 운영 지원
  • +
  • 고객사 요구 안전사항 대응
  • +
+

관리감독자 (부서별 안전관리 수행) :

+
    +
  • 부서 내 안전보건 점검 수행
  • +
  • 구성원 안전수칙 준수 관리
  • +
  • 위험요인 확인 및 개선조치
  • +
  • 사고 발생 시 보고 및 초기 대응
  • +
  • 안전보건 교육 참여 독려
  • +
+

안전보건 협의체 운영

+

임직원 의견수렴과 안전문화 정착을 위해 안전보건 관련 사항에 대해 정기적으로 협의하고 개선활동을 추진한다.

+
구분내용비고
기업명모비핀테크놀러지(주)
담당부서사업개발팀
담당자안전보건 경영담당 최준희 부장
제정일자2026년 5월 11일
개정이력Rev.0(최초제정)
+
+
+ + +
+
+
+ + + + + + diff --git a/index.html b/index.html new file mode 100644 index 0000000..489b303 --- /dev/null +++ b/index.html @@ -0,0 +1,139 @@ + + + + + + + MOBIPINTECH · Company Profile + + + + + + + + + + +
+
+ +
+
+

Automotive · Robotics · Solution · SI

+

차량과 디바이스,
서비스가 만나는 지점을 설계합니다.

+

+ 모비핀테크놀러지는 지난 10년간 스마트 플랫폼과 AI 로봇 개발을 거쳐 + 자동차 전장, 솔루션, SI 영역까지 확장해 온 Total SW 개발 회사입니다. +

+ +
+ +
+ +
+ +
+ +
+

Network, Data, Human을 연결하는 Total SW 개발 조직입니다.

+

+ AUTOSAR 기반 자동차 전장 개발, AI 기반 관제 스마트 플랫폼, 로봇 SW 개발 및 AI 플랫폼, + 웹·앱 SI 개발까지 다양한 R&D 및 협력 개발을 통해 양질의 기술 지원을 제공합니다. +

+
+
+
+ Automotive + AUTOSAR 기반 자동차 전장 개발 +

BSW, ASW, SBCM, 텔레매틱스 BSP, 검증 자동화까지 차량 소프트웨어 개발 대응.

+
+
+ Robotics / Solution + AI 로봇과 관제 플랫폼 +

로봇 안내, AI 챗봇, IoT 관제, 데이터 분석 기반의 운영 플랫폼 구축.

+
+
+ SI + 웹·앱 서비스 개발 +

업무 시스템, 관리자 콘솔, 모바일 앱, 서비스 UX까지 필요한 산출물을 통합 구현.

+
+
+
+ +
+ + Automotive Technical Capabilities + 전장 기술 역량 +

AUTOSAR, SBCM, BSP, HMI, 테스트 자동화까지 차량 소프트웨어 사례를 확인합니다.

+
+ + Robotics Technical Capabilities + 로봇 기술 역량 +

안내 로봇, 큐레이팅 로봇, 로봇 서비스 연동, AI 플랫폼 사례를 확인합니다.

+
+ + Solution Technical Capabilities + 솔루션 기술 역량 +

AI·IoT, 관제, 데이터 분석, 운영 플랫폼 등 솔루션 구축 사례를 확인합니다.

+
+ + SI Technical Capabilities + SI 개발사례 보기 +

웹, 앱, 관리자 콘솔, 업무 시스템 구축 사례를 확인합니다.

+
+
+
+ + + + + + diff --git a/js/capabilities-data.js b/js/capabilities-data.js new file mode 100644 index 0000000..471aabe --- /dev/null +++ b/js/capabilities-data.js @@ -0,0 +1,757 @@ +window.CAPABILITY_PROJECTS = [ + // P.12 + { + id: "sbcm-software-development", + type: "automotive", + category: "AUTOSAR ASW DEVELOPMENT", + title: "SBCM SW 개발", + description: `1·2세대 총 32개 차종에 적용되는 SBCM(Seat/Body Control Module) 소프트웨어를 개발하고, OMU, AFCU, CDM, E-LATCH, PDL, PDS, RDC, EHL 등 주요 차량 바디 제어 기능을 차종별 요구사항에 맞게 구현하였습니다. + +Mobilgene AUTOSAR 기반 환경에서 SWC(Software Component)를 구성하고 소프트웨어를 Build하여 차량 제어 시스템에 적용할 수 있는 개발 환경을 구축하였으며, 다양한 차종과 세대별 사양에 대응할 수 있도록 기능을 체계적으로 개발하였습니다. + +MATLAB Simulink를 활용한 Model 기반 Application Software 설계 및 검증을 수행하여 기능 요구사항을 모델로 구현하고 소프트웨어 동작을 검증하였습니다. 또한 Sleep/Wake-up, 진단 기능, HSM 보안 모듈, Fail-Safe 등 비기능 요구사항을 함께 개발하고 검증하였습니다. + +정적 및 동적 검증을 수행하고, QAC, CodeSonar, HKSAT, FossID 등 다양한 검증 Tool을 활용하여 소스 코드의 품질과 잠재적인 결함, 보안 취약 요소 등을 검증하였습니다. + +ISO 26262 기능 안전 개발 프로세스 기반 업무 (ASIL, FMEA, DFA) 를 수행하였습니다. +`, + scope: "Safety mechanism · Platform", + output: "SW module · Verification", + image: "assets/images/automotive/automotive_01_background.jpeg", + objectImage: "assets/images/automotive/automotive_01_object.png", + }, + // P.13 + { + id: "hvac-autosar-asw-development", + type: "automotive", + category: "AUTOSAR ASW DEVELOPMENT", + title: "차량용 공조제어기 SW 개발", + subtitle: "H-VAC Controller Application Software", + description: `기존 Non-AUTOSAR 기반으로 개발된 차량용 공조제어기 소프트웨어를 AUTOSAR 기반의 표준화된 구조로 전환하고, 소프트웨어 아키텍처 설계부터 기능 구현 및 검증까지 수행하였습니다. + +기존 소프트웨어의 기능과 구조를 분석하여 AUTOSAR 환경에 적합하도록 ASW(Application Software) 영역의 아키텍처를 새롭게 설계하고, 제어기 소프트웨어의 구성 요소를 체계적으로 재구성하였습니다. + +AUTOSAR ASW 구조에 따라 SWC(Software Component)를 생성하고 각 Component에 필요한 PORT와 Interface를 정의하였으며, Event 및 Runnable을 구성하여 소프트웨어 기능 간의 관계와 실행 구조를 설계하였습니다. + +RTE( Runtime Environment)를 Generate하고 BSW 영역과 연계하여 Application Software와 하위 소프트웨어 계층 간의 정상적인 기능 호출 및 데이터 통신이 가능하도록 통합 작업을 수행하였습니다. + +전환 과정에서 발생하는 기능 결함과 연계 오류에 대한 대응 업무를 수행하고, SW Test를 통해 각 기능의 정상 동작 여부를 검증하였습니다. + + Non-AUTOSAR 기반의 기존 공조제어기 소프트웨어를 AUTOSAR 표준 구조로 성공적으로 전환하고, ASW 아키텍처 설계부터 SWC 구성, RTE Generate 및 BSW 연계, SW Test와 결함 분석·Debugging까지 전반적인 AUTOSAR 전환 및 검증 업무를 수행하였습니다. +`, + scope: "BDC · Log analysis · Reprogramming", + output: "Issue report · Tool flow", + image: "assets/images/automotive/automotive_02_background.png", + objectImage: "assets/images/automotive/automotive_02_object.png", + }, + // P.14 + { + id: "autonomous-vehicle-fcm-controller", + type: "automotive", + category: "AUTOSAR BSW DEVELOPMENT", + title: "Autonomous Vehicle FCM 제어기 개발", + subtitle: "Front Camera Module Controller", + description: `자율주행 차량의 핵심 전장 기능을 안정적으로 지원할 수 있도록 AUTOSAR 기반 FCM 제어기의 소프트웨어 아키텍처 설계 및 핵심 모듈 통합 개발을 수행하였습니다. + +AUTOSAR BSW 아키텍처를 기반으로 제어기 소프트웨어 구조를 설계하고 주요 BSW 모듈을 통합하여 차량 전장 환경에 적합한 소프트웨어 플랫폼을 구성하였습니다. + +차량 진단 기능을 위한 Application을 개발하고 Cyber Security 관련 사양과 연계하여 ASK 등의 보안 기능을 적용하였으며, CAN 및 CAN-FD 기반 차량 통신 기능을 구현하여 차량 네트워크와의 안정적인 데이터 연계가 가능하도록 구성하였습니다. 또한 DCM을 비롯한 일부 하위 CAN 및 Ethernet AUTOSAR Layer Stack을 개발하였습니다. + +ISO 및 OEM 요구사항을 기반으로 DoCAN 및 DoIP Stack을 개발하여 CAN 및 Ethernet 환경에서의 진단 통신 기능을 구현하였으며, Bootloader 진단 사양과 Reprogramming 기능을 개발하여 제어기의 안정적인 소프트웨어 업데이트 환경을 구축하였습니다. 이와 함께 Application 영역의 진단 사양을 개발하여 제어기 내부 기능과 진단 시스템 간의 연계성을 확보하였습니다. + +이를 통해 AUTOSAR 기반 BSW 아키텍처 설계 및 모듈 통합부터 차량 통신, 진단 Application, Cyber Security, Bootloader 및 DoCAN·DoIP 통신 Stack까지 FCM 제어기 개발에 필요한 핵심 소프트웨어 영역을 종합적으로 구현하였습니다. +`, + scope: "AUTOSAR · Multicore · Porting", + output: "Porting guide · ASW", + image: "assets/images/automotive/automotive_03_background.png", + objectImage: "assets/images/automotive/automotive_03_object.png", + }, + // P.15 + { + id: "hvac-autosar-bsw-development", + type: "automotive", + category: "AUTOSAR BSW DEVELOPMENT", + title: "차량용 공조제어기 SW 개발", + subtitle: "H-VAC Controller Basic Software", + description: `차량용 공조제어기의 안정적인 소프트웨어 동작과 차량 전장 시스템과의 원활한 연계를 위해 AUTOSAR 기반의 BSW 및 Middleware를 개발하고, 제어기의 핵심 기능과 진단·보안·업데이트 기능을 통합 구현하였습니다. + +FBL(Flash Boot Loader) 기능을 구현하고 Sleep & Wake-up 사양을 개발하여 차량의 전원 상태 변화에 따른 제어기의 안정적인 동작 환경을 확보하였습니다. BSW Configuration 및 Implementation을 수행하고 Middleware를 구현하였으며, M-CAL Port를 비롯하여 ADC, PWM, ICU, IoHwAb, OS 등 주요 AUTOSAR 모듈을 설정하고 제어기 사양에 맞게 통합하였습니다. + +또한 CAN 요구사항을 반영하여 관련 DB를 Import하고 Generate 및 Harmonize 과정을 수행함으로써 차량 네트워크 환경과 제어기 소프트웨어 간의 통신 연계성을 구현하였습니다. + +보안 기능 강화를 위해 HSM, ASK, SFM 및 Crypto Library를 포팅하고 기능 검증을 수행하여 차량용 제어기에 요구되는 보안 기능을 안정적으로 적용하였습니다. 진단 영역에서는 DiagDCM 및 DEM Configuration을 수행하고 관련 기능을 검증하여 차량 진단 시스템과 제어기 간의 안정적인 진단 환경을 구축하였습니다. + +OTA(Over-The-Air) 기반 Background 및 Reprogramming 기능을 개발하고 검증하여 차량 소프트웨어를 안정적으로 업데이트할 수 있는 환경을 구현하였습니다. Watch-Dog 요구사항을 반영 개발하였습니다.`, + scope: "H-VAC Controller Basic Software", + output: "Control module · QA", + image: "assets/images/automotive/automotive_04_background.jpeg", + objectImage: "assets/images/automotive/automotive_04_object.png", + }, + // P.16 + { + id: "a-spice-swe5-integration-verification", + type: "automotive", + category: "VERIFICATION", + title: "A-SPICE 기반 SWE5 통합검증", + subtitle: "Software Engineering Process Integration Test", + description: `자동차 소프트웨어 개발 프로세스의 품질과 신뢰성을 확보하기 위해 A-SPICE 기반 SWE5 Software Integration Test 환경을 구축하고 소프트웨어 통합검증을 수행하였습니다. + +요구사항 및 소프트웨어 설계 분석을 기반으로 테스트 범위를 정의하고,검증 목적에 적합한 Test Case를 개발하여 소프트웨어 구성 요소 간 통합 동작과 기능을 체계적으로 검증하였습니다. + +HKMC ES 95490-10 기준에 따라 소프트웨어 통합검증을 수행하고, 테스트 결과에 대한 Coverage를 분석하여 검증 범위와 결과를 정량적으로 관리할 수 있도록 하였습니다. + +테스트 과정에서 발생한 이상 동작 및 이슈에 대해서는 원인을 분석하고 결과를 체계적으로 관리하였으며, 검증 결과와 이슈 분석 내용을 기반으로 테스트 리포트 및 관련 산출물을 작성·관리하였습니다. + +또한 다양한 검증 Tool을 활용하여 테스트 실행 및 결과를 관리하고, Vector 서버 기반의 테스트 환경을 구축하여 통합 테스트 수행과 결과 관리를 지원하였습니다. +`, + scope: "SWE5 · Validation · Test", + output: "Test scenario · Report", + image: "assets/images/automotive/automotive_05_background.png", + objectImage: "assets/images/automotive/automotive_05_object.png", + }, + // P.17 + { + id: "ldm-controller-verification", + type: "automotive", + category: "VERIFICATION", + title: "LDM 제어기 검증", + subtitle: "LED Driving Module", + description: `차량용 LDM 제어기의 안정적인 동작과 기능 신뢰성을 확보하기 위해 전원 및 입력 신호, 출력 특성, 부하 대응, 주요 Test Point 및 기능 동작에 대한 종합적인 검증을 수행하였습니다. + +초기 전원 인가에 따른 제어기의 동작 안정성을 확인하고, Duty 및 Frequency 변화에 따른 PWM 신호 특성과 Decade 저항 변화에 대한 입력 대응성을 검증하여 다양한 입력 조건에서의 정상 동작 여부를 확인하였습니다. + +전 채널의 LED 부하 출력 기능을 검증하고 채널별 특성 전류를 측정하여 데이터를 체계적으로 기록하였으며, Electronic Load와 연동한 테스트를 통해 다양한 부하 조건에서의 출력 특성과 안정성을 검증하였습니다. +또한 주요 Test Point의 전압 및 신호 파형을 측정하고 데이터를 정량화하여 Oscilloscope 기반으로 이상 동작의 원인과 결함 발생 요인을 분석하였습니다. + +고객사에서 제공한 Test Case를 기반으로 제어기의 주요 기능에 대한 종합적인 동작 검증을 수행하고, 테스트 과정에서 발생한 이상 동작 및 불량 현상에 대해 원인을 추적하여 문제점을 분석하였습니다. +테스트 결과와 결함 원인 분석 내용을 정량적인 데이터로 정리하고, 종합 분석 리포트 및 결과 보고서를 산출하여 제어기의 기능 안정성과 품질 신뢰성을 객관적으로 검증할 수 있도록 지원하였습니다. + +`, + scope: "LDM · Controller · QA", + output: "Validation matrix", + image: "assets/images/automotive/automotive_06_background.png", + objectImage: "assets/images/automotive/automotive_06_object.png", + }, + // P.18 + { + id: "hvac-es-specification-verification", + type: "automotive", + category: "VERIFICATION", + title: "공조제어기 ES 사양 검증", + subtitle: "H-VAC Controller ES Specification Verification", + description: `차량 공조제어기의 전장 소프트웨어 안정성과 보안성을 확보하기 위해 진단통신, 하드웨어 보안 모듈 및 소프트웨어 업데이트 기능에 대한 ES 사양 검증을 수행하였습니다. + +UDS 기반 진단통신 평가를 통해 제어기와 진단 시스템 간 통신 사양 및 주요 진단 기능을 검증하고, 차량 전장 시스템의 안정적인 진단 환경을 확보하였습니다. + +HSM(Hardware Security Module) 기반 보안 모듈에 대한 검증을 비롯하여 암호화 알고리즘, Secure Boot 및 소프트웨어 무결성 검증을 수행함으로써 제어기 소프트웨어의 보안성과 신뢰성을 확보하였습니다. +또한 TP 제어기의 보안 리프로그래밍(Secure Flash 2.0) 기능을 검증하여 소프트웨어 업데이트 과정에서의 보안 요구사항과 정상적인 리프로그래밍 동작을 확인하였습니다. + +1·2세대 유·무선 소프트웨어 업데이트 시스템(OTA)에 대한 기능 및 통신 검증을 수행하고, H-OTA Studio와 연계하여 다양한 OTA 시나리오를 구성하고 실제 통신 과정을 검증하였습니다. +`, + scope: "BSP · Qualcomm · MediaTek", + output: "Board bring-up · Stabilization", + image: "assets/images/automotive/automotive_07_background.jpeg", + objectImage: "assets/images/automotive/automotive_07_object.png", + }, + // P.19 + { + id: "automotive-log-acquisition-reprogramming", + type: "automotive", + category: "REPROGRAMMING", + title: "전장 SW 로그정보 취득 및 리프로그래밍", + subtitle: "Log Information Acquisition & Reprogramming", + description: `현대자동차 울산공장, 남양연구소 등 전국 주요 SITE를 직접 방문하여 실차 기반의 전장 SW Re-Work 및 대규모 리프로그래밍 이슈에 대응하고, 차량 전장 시스템의 안정적인 소프트웨어 운영을 지원하였습니다. + +SOP 단계에서 발생하는 다양한 현장 이슈를 신속하게 분석하고 대응할 수 있도록 로그 정보 취득부터 제어기 업데이트 및 교체까지 실차 중심의 기술 지원 업무를 수행하였습니다. + +CANalyzer를 활용하여 실차에서 발생하는 각종 CAN 로그 및 전장 시스템 정보를 취득하고 분석하여 문제 상황을 파악할 수 있도록 하였으며, 진단기를 이용하여 다양한 제어기의 소프트웨어 업데이트 및 리프로그래밍을 +수행하였습니다. 또한 실차량의 탈거 작업을 통한 BDC(Body Domain Controller) 제어기 교체와 FOB 작업을 통한 스마트 키 보드 교체 및 재설정 등 차량 전장 부품에 대한 현장 작업을 함께 수행하였습니다. + +특히, SOP 단계에서 발생한 대규모 리프로그래밍 이슈에 대해 다수의 전문 인력을 현장에 투입하여 전국 각 SITE에서 신속하게 Re-Work를 수행하고, 차량별 상황에 따른 로그 취득·분석 및 제어기 업데이트를 진행하였습니다. + +이를 통해 양산 단계에서 발생할 수 있는 전장 SW 이슈에 대한 현장 대응력을 확보하고, 차량의 소프트웨어 및 전장 시스템이 안정적으로 정상화될 수 있도록 지원하였습니다. +`, + scope: "ADAS · BSW · Diagnostics", + output: "BSW module · Interface", + image: "assets/images/automotive/automotive_08_background.png", + objectImage: "assets/images/automotive/automotive_08_object.png", + }, + // P.20 + { + id: "oem-navigation-engine-hmi", + type: "automotive", + category: "NAVIGATION", + title: "순정 NAVI 엔진앱 / HMI 개발", + subtitle: "Genuine Navigation Engine App / HMI Development", + description: `현대·기아 차량에 적용되는 순정 내비게이션의 엔진 및 HMI를 개발하고, 브랜드·차종·지역별 요구사항에 유연하게 대응할 수 있는 공통 개발 환경을 구축하였습니다. + +코드 일원화를 통해 브랜드 및 차종, 지역에 따라 개별적으로 발생하는 개발 요소를 효율적으로 관리하고, 공통 기능의 재사용성을 높여 내비게이션 개발 및 유지보수의 효율성을 향상시켰습니다. + +정적 분석 Tool을 활용하여 소스 코드의 잠재적인 오류와 품질을 점검하고 코드 안정성을 확보하였으며, 내비게이션과 센터 서버 간 실시간 업데이트 기능을 개발하여 최신 정보와 서비스가 차량 내 내비게이션에 신속하게 반영될 수 있도록 구현하였습니다. +또한 차량 시스템과 내비게이션 간 Interface를 개발하여 각 시스템 간 안정적인 데이터 및 기능 연계가 가능하도록 구성하였습니다. + +이와 함께 차량의 주행 특성을 고려한 N-mode(서킷) 기능 개발에 참여하여 특수 주행 환경에 대응할 수 있는 내비게이션 기능을 확장하였으며, 지도 화면에 부동산 정보를 연동하여 기존 길안내 중심의 내비게이션에서 다양한 생활·부가 정보를 함께 제공할 수 있도록 기능을 확대하였습니다. + +이를 통해 공통 코드 기반의 개발 효율성과 소프트웨어 안정성을 확보하고, 차량 시스템·서버·지도 데이터 등 다양한 요소와의 연계를 통해 현대·기아 순정 내비게이션의 서비스 확장성과 사용자 편의성을 향상시켰습니다. +`, + scope: "Field rework · CAN log · Reprogramming", + output: "Site support · Report", + image: "assets/images/automotive/automotive_09_background.jpeg", + objectImage: "assets/images/automotive/automotive_09_object.png", + }, + // P.21 + { + id: "automotive-project-history", + type: "automotive", + category: "Automotive", + title: "전장 - ETC", + layout: "table", + image: "assets/images/automotive/automotive_10_background.jpg", + tableHeaders: ["사업명", "사업기간"], + tableRows: [ + ["EB AutoSAR 기반 Platform 및 Safety Mechanism SW 개발", "2026. 04 ~"], + ["JS TECH KA5 T-CAR BSW 개발", "2026.01 ~ 2026.03"], + [ + "EB Safety Classic AutoSAR Multicore Porting 및 Application 개발", + "2025. 11 ~ 2026.03", + ], + ["현대차 BDC 제어기 전장 SW 로그 분석 및 리프로그래밍 과제", "2025.09 ~"], + [ + "HL KLEMOVE SRR-40DF 제어기 보드 Ethernet Bootloader 개발", + "2025.01 ~ 2025.06", + ], + [ + "HL KLEMOVE 자율주행 ADAS_DRV 제어기 AUTOSAR BSW 개발", + "2024.01 ~ 2025.12", + ], + ["JS TECH ASW 컨설팅", "2023.04 ~ 2023.10"], + ["대우전자부품 CCH 제어기 AUTOSAR BSW 컨설팅", "2024.05 ~ 2024.12"], + ["SL 2세대 SBCM 제어기 SW 개발", "2023.12 ~ 2025.03"], + ["SL AUTOSAR SW 통합 및 비기능 SW 개발", "2023.05 ~ 2024.12"], + [ + "LG전자 VS 사업부 Honda, Toyota, BMW 제어기 Modem BSP 개발", + "2022.04 ~ 2023.07", + ], + ], + }, + // P.23 + { + id: "guide-curating-robot", + type: "robotics", + category: "Android", + title: "가이드 및 큐레이팅 봇 개발", + subtitle: "Guide & Curating Robot Development", + description: `사용자가 필요한 정보를 쉽고 빠르게 확인하고 목적지까지 편리하게 이동할 수 있도록 가이드봇 UI와 챗봇, AR 기반 길안내 기능을 연계한 가이드 및 큐레이팅 봇을 개발하였습니다. + +직관적인 가이드봇 UI와 서비스 화면을 구성하여 사용자가 다양한 안내 정보를 편리하게 확인하고 서비스 기능을 자연스럽게 이용할 수 있도록 구현하였습니다. + +챗봇과 연계한 동적 개발을 통해 사용자의 질문과 요청에 따라 필요한 정보를 제공할 수 있도록 구성하였으며, AR 기반 길안내 기능을 적용하여 실제 공간에서 이동 경로와 목적지를 직관적으로 확인할 수 있도록 하였습니다. +또한 QR 기반 접수 정보와 전자카드를 연동하여 별도의 복잡한 절차 없이 접수 및 관련 정보를 확인하고 이용할 수 있는 편의 기능을 제공하였습니다. + +이를 통해 단순한 정보 안내를 넘어 챗봇을 통한 정보 제공, AR 기반 공간 안내, QR 및 전자카드 연동 등 다양한 기능을 하나의 서비스로 통합하여 사용자의 정보 접근성과 이동 편의성을 높였습니다. 또한 서비스 특성에 맞는 UI를 구축하여 가이드 및 큐레이팅 서비스의 이용 편의성과 운영 효율성을 향상시킬 수 있는 사용자 중심의 안내 환경을 구현하였습니다. +`, + scope: "Guide robot · Museum · UI", + output: "Robot screen · Scenario", + image: "assets/images/robotics/robotics_01_background.png", + objectImage: "assets/images/robotics/robotics_01_object.png", + }, + // P.24 + { + id: "air-purifying-robot", + type: "robotics", + category: "Robotics", + title: "공기청정기 로봇 개발", + subtitle: "Air-Purifying Robot Development", + description: `AI 자율주행 기술을 기반으로 실내 공간을 이동하며 공기질을 관리하고, 사용자와의 상호작용 및 생활 편의 기능까지 제공할 수 있는 공기청정기 로봇을 개발하였습니다. + +공간 내 사각지대를 최소화할 수 있도록 자율주행 기반의 이동 청정 기능을 구현하고, 주변 환경을 감지하여 상황에 맞게 대응할 수 있도록 구성함으로써 보다 효율적인 실내 공기 관리 환경을 제공합니다. + +Google Gemini를 탑재하여 사용자의 간단한 질문이나 안내 요청에 응답하고 일상적인 대화가 가능하도록 구현하였으며, 접촉 없이 약 10초 이내에 체온 등 건강 관련 신호를 확인할 수 있는 기능을 제공하여 공기청정 기능을 넘어 사용자의 일상적인 건강관리까지 지원할 수 있도록 구성하였습니다. + +또한 개인정보 보호와 데이터 보안을 고려하여 사용자 데이터가 안전하게 관리될 수 있도록 보안 환경을 적용하였으며, 향후 사용자의 생활 패턴과 요구에 따라 나만의 주치의, 시큐리티 등 다양한 기능을 지속적으로 확장할 수 있는 기반을 마련하였습니다. + +이를 통해 공기질 관리와 AI 기반 사용자 인터랙션, 건강 신호 확인, 보안 및 생활 편의 기능을 하나의 로봇에 통합하여 일상 공간에서 다양한 서비스를 제공할 수 있는 지능형 공기청정 로봇 환경을 구현하였습니다. +`, + scope: "Robot service · Guidance", + output: "Service flow · API", + image: "assets/images/robotics/robotics_02_background.png", + objectImage: "assets/images/robotics/robotics_02_object.png", + objectLayout: { + x: "calc(100% - 126px)", + y: "calc(100% - 86px)", + anchorX: "-100%", + anchorY: "-100%", + width: "auto", + height: "auto", + maxHeight: "560px", + }, + }, + // P.25 + { + id: "smart-care-robot", + type: "robotics", + category: "Robotics", + title: "스마트돌봄 사업 봇 개발", + subtitle: "Smart Care Service Robot Development", + description: `아동을 대상으로 실시간 교육과 비대면 상담, 인공지능 기반 학습 및 놀이 활동, 로봇을 활용한 인지·정서 평가를 제공할 수 있도록 스마트돌봄 사업 봇을 개발하였습니다. + +화상장비를 활용한 양방향 화상교육 및 비대면 상담 기능을 제공하여 시간과 장소의 제약을 최소화하고, 아동과 교육 및 상담 담당자 간 원활한 실시간 소통이 가능하도록 구성하였습니다. + +생성형 인공지능을 활용하여 아동의 학습과 놀이 활동을 지원하는 프로그램을 제공하고, 창의력·어휘력·사고력 향상을 위한 다양한 콘텐츠를 구성하여 아동이 흥미를 가지고 자연스럽게 학습에 참여할 수 있도록 구현하였습니다. 또한 로봇을 활용한 인지·정서 평가 프로그램을 통해 아동의 활동 및 반응을 기반으로 인지능력을 측정하고 관리할 수 있는 기능을 제공하였습니다. + +이를 통해 화상 기반 교육 및 상담, 생성형 AI 기반 학습·놀이 서비스, 로봇 기반 인지·정서 평가와 운영 관리 기능을 하나의 환경으로 통합하여 아동의 학습과 돌봄을 효과적으로 지원할 수 있는 스마트돌봄 플랫폼을 구현하였습니다. +`, + scope: "Guide robot · Telecom · Integration", + output: "Robot integration", + image: "assets/images/robotics/robotics_03_background.png", + objectImage: "assets/images/robotics/robotics_03_object.png", + }, + // P.26 + { + id: "robot-english-content-platform", + type: "robotics", + category: "Robotics", + title: "로봇 영어 제작 플랫폼", + subtitle: "AI English Tutoring Robot Platform", + description: `로봇을 활용하여 아동의 흥미와 참여를 유도하고, 놀이와 학습을 자연스럽게 결합한 영어 학습 환경을 제공할 수 있도록 로봇 영어 제작 플랫폼을 구축하였습니다. + +아동이 로봇과 직접 상호작용하며 학습할 수 있도록 활동 감지 및 터치 센서를 적용하여 학습 참여도를 높이고, 안전한 환경에서 언어 학습을 실천할 수 있도록 구성하였습니다. + +아동의 행동 및 이용 패턴을 분석하여 개인의 관심과 활동 특성에 맞는 최적화된 정보 서비스를 제공할 수 있도록 구현하였습니다. + +화장실 이용 횟수 및 시간대, 시소·그네·미끄럼틀 등 선호하는 놀이 요소와 같은 데이터를 활용하여 아동의 행동 특성을 파악하고, 축적된 데이터를 기반으로 보다 효과적인 학습 및 관리 서비스를 제공할 수 있도록 하였습니다. 또한 관리자 모드를 통해 연령대 및 성별에 따른 학습 콘텐츠를 관리하고, 게임 콘텐츠의 등록 및 운영, 스케줄 관리 등의 기능을 제공하여 관리자가 교육 환경을 효율적으로 운영할 수 있도록 구성하였습니다. +`, + scope: "Chatbot · Intent · Content", + output: "Conversation map", + image: "assets/images/robotics/robotics_04_background.png", + objectImage: "assets/images/robotics/robotics_04_object.png", + }, + // P.28 + { + id: "tpms-integrated-solution", + type: "solution", + category: "솔루션 개요", + title: "TPMS 통합 솔루션", + subtitle: "Integrated TPMS Solution", + description: `TPMS 통합 솔루션은 교육, 산업, 방송 등 다양한 플랫폼 환경에서 발생하는 데이터를 통합적으로 관리하고 분석할 수 있도록 지능형 기술을 적용한 Total Platform Management System 입니다. + +빅데이터를 기반으로 플랫폼에서 생성되는 다양한 데이터를 수집·분석하고, 딥러닝 및 머신러닝 기술을 활용하여 단순한 현황 및 통계 정보 제공을 넘어 데이터 기반의 소요예측과 미래지향적 분석 기능을 구현하였습니다. 이를 통해 반복적으로 수행되는 관리 업무를 자동화할 수 있고, 축적된 데이터를 기반으로 주요 업무 및 운영 현황을 지능적으로 분석할 수 있습니다. 또한 플랫폼별로 분산되어 있는 데이터를 체계적으로 관리하고 통계 및 분석 결과를 제공함으로써 운영 효율성을 높이고, 데이터에 기반한 의사결정이 가능하도록 구성하였습니다. + +특히, 지능형 데이터 분석을 통해 향후 발생 가능한 수요와 운영 결과를 예측할 수 있는 기반을 마련하여, 교육·산업·방송 분야의 다양한 플랫폼 운영 환경에 대응할 수 있는 미래지향적인 통합 관리 솔루션으로 활용될 수 있도록 개발하였습니다. +`, + scope: "IoT · AI · Platform", + output: "Service architecture", + image: "assets/images/solution/solution_01_background.jpeg", + objectImage: "assets/images/solution/solution_01_object.png", + }, + // P.29 + { + id: "location-based-advertisement-system", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "위치 기반 광고 송출 시스템", + subtitle: "Location Based Advertisement Broadcasting System", + description: `버스, 지하철 등 대중교통 이용 환경에서 사용자의 위치와 이동 경로를 기반으로 맞춤형 광고 및 교통 정보를 제공할 수 있도록 위치 기반 관제 및 광고 송출 시스템을 TPMS 통합 솔루션으로 구축하였습니다. + +GPS 기반의 위치 정보를 활용하여 대중교통의 이동 상황을 실시간으로 분석하고, 이용자의 이동 위치에 따라 도착 정류장 안내, 정류장 주변 맞춤형 광고, 도착 정류장 주변의 연계 교통 정보 등 위치와 상황에 최적화된 콘텐츠를 제공할 수 있도록 구현하였습니다. + +이를 통해 단순한 광고 송출을 넘어 대중교통 이용자의 이동 상황과 연계된 정보성 콘텐츠를 함께 제공하여 광고의 활용성과 서비스 편의성을 높였습니다. + +특히, GPS 좌표의 흔들림 현상과 각 정류장 및 버스의 이동 방향을 정밀하게 분석하기 위해 벡터의 내적을 활용한 자체 개발 버스 GPS 엔진을 적용하여 버스의 실제 이동 방향과 정류장 간의 위치 관계를 분석하고, 현재 위치 및 도착 정류장을 보다 정확하게 판단할 수 있도록 하여 위치 기반 광고 송출과 교통 정보 제공의 정확도를 향상시켰습니다. +`, + scope: "Report automation · Data", + output: "Dashboard · Report", + image: "assets/images/solution/solution_02_background.png", + objectImage: "assets/images/solution/solution_02_object.png", + }, + // P.30 + { + id: "corporate-broadcast-system", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "사내방송 시스템", + subtitle: "Internal Office Broadcasting & Monitoring System", + description: `전사 및 지점, 부서 단위의 사내 방송을 효율적으로 운영하고 관리할 수 있도록 통합 모니터링 기반의 사내방송 시스템을 TPMS 통합 솔루션으로 구축하였습니다. + +방송 현황과 각종 방송 장비의 연결 및 운영 상태를 한눈에 확인할 수 있도록 구성하여 관리자가 전체 방송 환경을 효율적으로 모니터링할 수 있도록 지원하였습니다. + +원격 전원 및 음량 제어, 장비 재시작 등의 기능을 제공하여 현장에 직접 방문하지 않고도 장비를 관리할 수 있도록 하였으며, 지점 및 부서별 장비 그룹 관리와 방송 스케줄 설정을 통해 대상과 상황에 맞는 맞춤형 방송 정보를 전달할 수 있도록 구현하였습니다. 또한 영상, 이미지, 웹, 오디오 등 +다양한 형태의 콘텐츠를 지원하여 사내 공지 및 정보 전달의 효과를 높였습니다. + +콘텐츠 동기화 기능과 장비별 상태 확인 기능을 통해 전사 방송 콘텐츠의 일관성을 유지하고, 방송 장비의 운영 상태를 체계적으로 관리할 수 있도록 구성하였습니다. +이를 통해 사내방송 운영에 필요한 관리 업무를 통합하고 현장 관리 부담을 최소화하여, 안정적인 방송 서비스 운영과 전반적인 관리 효율성을 향상시켰습니다. +`, + scope: "Education · Operation", + output: "Admin · User service", + image: "assets/images/solution/solution_03_background.png", + objectImage: "assets/images/solution/solution_03_object.png", + }, + // P.31 + { + id: "automotive-photozone-3d-solution", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "자동차 포토존 3D 촬영 솔루션", + subtitle: "Vehicle Photozone 3D Video Capture System", + description: `자동차 포토존 3D 촬영 솔루션은 자동차를 다양한 각도에서 촬영하여 차량의 외관을 360도 콘텐츠로 제작하고, 이를 온라인 차량 소개 및 비대면 상담에 활용할 수 있는 Hardware & Software 종합 시스템 솔루션 입니다. + +턴테이블을 활용하여 차량을 일정한 각도로 회전시키면서 촬영함으로써 촬영 각도와 품질의 일관성을 확보하고, 키오스크를 통해 촬영 과정을 간편하게 조작할 수 있도록 구현하여 작업자의 편의성과 운영 효율성을 높였습니다. 또한 모바일 기기를 촬영 장비로 활용할 수 있도록 구성하여 별도의 전문 촬영 장비에 대한 부담을 줄이고 다양한 환경에서 유연하게 운영할 수 있도록 하였습니다. + +차량을 반복적으로 이동하거나 촬영자가 차량 주변을 직접 이동하며 촬영해야 하는 작업을 최소화하여 촬영에 소요되는 시간과 작업 부담을 줄였으며, 촬영된 이미지를 기반으로 3D 모바일 뷰어와 연계하여 실제 차량을 다양한 각도에서 확인할 수 있는 콘텐츠를 제공합니다. + +이를 통해 오프라인 전시 및 촬영 중심의 차량 소개 방식을 온라인 환경으로 확장하고, 고객이 시간과 장소의 제약 없이 차량의 외관을 확인하고 비대면 상담까지 활용할 수 있는 디지털 차량 콘텐츠 환경을 구현하였습니다. +`, + scope: "IP · Matching · Workflow", + output: "Web platform", + image: "assets/images/solution/solution_04_background.png", + objectImage: "assets/images/solution/solution_04_object.png", + objectLayout: { + x: "100%", + y: "calc(100% - 86px)", + anchorX: "-98%", + anchorY: "-100%", + height: "auto", + maxHeight: "none", + }, + }, + // P.32 + { + id: "3d-capture-management-system", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "3D 촬영 관리 시스템", + subtitle: "3D Video Capture Management System", + description: `중고차 매물 등록 과정에서 발생하는 현장 촬영과 등록 업무를 효율적으로 관리할 수 있도록 촬영 관리 시스템을 자동차 포토존 3D 촬영 솔루션으로 구축하였습니다. + +현장에서 차량 확인부터 촬영, 사진 관리 및 매물 등록에 필요한 업무를 하나의 흐름으로 처리할 수 있도록 구성하여 반복적인 정보 입력과 사진 파일 전달 등의 불필요한 작업을 최소화하고 매물 등록에 소요되는 업무 시간을 단축하였습니다. + +차량별로 등록에 필요한 필수 촬영 장면과 촬영 가이드라인을 모바일 앱에서 제공하여 작업자가 촬영 순서와 기준을 쉽게 확인할 수 있도록 하였으며, 이를 통해 작업자에 따라 달라질 수 있는 촬영 결과의 편차를 줄이고 일관된 품질의 매물 이미지를 확보할 수 있도록 구현하였습니다. 또한 촬영된 사진을 차량 정보와 연계하여 체계적으로 관리할 수 있도록 하고, 촬영 결과의 임시저장 및 업로드 상태를 앱과 관리자 시스템에서 확인할 수 있도록 구성하였습니다. + +기존에 등록된 차량의 정보와 촬영 현황 또한 앱 및 관리자 시스템을 통해 확인할 수 있도록 하여 현장 작업과 관리 업무 간의 연계성을 높이고, 중고차 매물 등록 업무의 전반적인 운영 효율성과 관리 편의성을 향상시켰습니다. +`, + scope: "Monitoring · Sensor · Control", + output: "Control room · Alert", + image: "assets/images/solution/solution_05_background.png", + objectImage: "assets/images/solution/solution_05_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // P.33 + { + id: "bogoworks-platform", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "보고웍스 플랫폼", + subtitle: "Automation Reporting and Management Platform Solution", + description: `보고웍스 플랫폼은 프로젝트의 작업 진행 현황과 관련 자료를 통합적으로 관리하고 관리자와 현업 종사자 간의 원활한 업무 소통을 지원할 수 있는 솔루션입니다. + +실시간 작업 진행 상황을 공유하고 확인할 수 있도록 구성하여 프로젝트 수행 과정에서 발생하는 업무 현황을 신속하게 파악하고 효율적으로 협업할 수 있도록 하였습니다. + +프로젝트 유형별 관리 기능을 통해 다양한 프로젝트의 업무와 진행 상황을 체계적으로 관리할 수 있도록 하였으며, 자동보고서 기능을 적용하여 프로젝트 진행 과정에서 필요한 보고서를 효율적으로 생성하고 관리할 수 있도록 구현하였습니다. 이를 통해 반복적인 보고서 작성 업무를 줄이고 보고 내용의 정확성과 신뢰성을 높일 수 있도록 지원하였습니다. 또한 프로젝트별로 생성되는 각종 자료와 업무 정보를 데이터화하여 체계적으로 축적하고 관리할 수 있도록 구성하였습니다. + +이를 통해 프로젝트 종료 및 담당자 변경 시 필요한 자료를 효율적으로 공유하고 인수인계할 수 있는 환경을 제공하며, 축적된 프로젝트 정보를 기반으로 업무 연속성을 확보하고 전반적인 프로젝트 관리 효율성을 향상시켰습니다. +`, + scope: "3D capture · Vehicle retail", + output: "Capture flow · Viewer", + image: "assets/images/solution/solution_06_background.jpeg", + objectImage: "assets/images/solution/solution_06_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // P.34 + { + id: "intelligent-student-management-platform", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "지능형 학생관리 통합 플랫폼", + subtitle: "Intelligent Student Management Integrated Platform", + description: `지능형 학생관리 통합 플랫폼은 학생관리 업무의 체계적인 운영과 효율적인 관리를 위해 상호호환되는 다양한 관리 시스템을 하나로 통합한 지능형 솔루션입니다. + +학생의 현재 상태와 출입 및 퇴실 정보를 통합적으로 관리하고, 관리자와 학생 부모가 관련 정보를 실시간으로 확인하고 소통할 수 있도록 구성하여 학생 관리의 신속성과 편의성을 높였습니다. + +관리자 간에도 학생 및 업무 관련 정보를 원활하게 전달하고 공유할 수 있도록 협업 기능을 제공하여 담당자 간 업무 연계성을 강화하였으며, 실시간으로 변화하는 학생 정보를 기반으로 보다 효율적인 관리와 대응이 가능하도록 구현하였습니다. 또한 전체 관리체계를 5개의 주요 분야로 세분화하여 각 관리자가 담당 업무에 집중하고 해당 영역을 보다 체계적이고 심도 있게 관리할 수 있도록 구성하였습니다. + +이를 통해 분산되어 있던 학생관리 업무와 정보를 통합하고, 관리자와 학생 부모 간의 실시간 정보 공유 및 관리자 간 협업을 지원하여 학생관리 업무의 효율성과 운영 편의성을 향상시켰습니다. +`, + scope: "Big data · Analytics", + output: "Pipeline · Dashboard", + image: "assets/images/solution/solution_07_background.jpeg", + objectImage: "assets/images/solution/solution_07_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // P.35 + { + id: "coastal-skyrail-operation-monitoring", + type: "solution", + category: "TPMS 통합 솔루션 적용분야", + title: "해안 스카일 레일 운영 관제", + subtitle: "Costline Sky Rail Operation Monitoring System", + description: `해안 스카이레일 관제 솔루션은 스카이레일의 운행 상태를 실시간으로 모니터링 하고 통합 관리하기 위한 스마트 관제 시스템입니다. + +차량의 위치와 운행 상태를 실시간으로 확인할 수 있으며, 운행 정보와 설비 상태를 통합 관제하여 안전한 운행과 효율적인 운영 관리를 할 수 있도록 개발하였습니다. + +차량은 배터리 상태, 속도, 운행 위치를 관제할 수 있으며 설비의 이상 상태를 실시간으로 감지하여 관제자에게 알려줍니다. + +또한, 운행 이력과 데이터를 통해 운영 분석을 지원하여 원활한 유지보수를 지원할 수 있도록 하였습니다. +`, + scope: "Face recognition · AI", + output: "Recognition module", + image: "assets/images/solution/solution_08_background.jpg", + objectImage: "assets/images/solution/solution_08_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // Certifications + { + id: "voiso-cms-patents", + type: "certifications", + layout: "certifications", + category: "CERTIFICATIONS", + title: "VOISO CMS 시스템 관련 특허증", + description: + "VOISO CMS 시스템과 관련된 특허를 취득하여 데이터 처리 및 관리 기술에 대한 지식재산을 확보했습니다.", + scope: "Patent · VOISO CMS", + image: "", + objectImage: "assets/images/patents/patents_01_object.jpg", + objectImageSecondary: "assets/images/patents/patents_01_object_02.jpg", + objectLayout: { + x: "49%", + y: "93%", + width: "26%", + height: "74%", + maxHeight: "none", + }, + objectLayoutSecondary: { + x: "78%", + y: "93%", + width: "26%", + height: "74%", + maxHeight: "none", + }, + }, + // P.37 + { + id: "autosar-integration-automation-platform", + type: "si", + category: "개발 사례", + title: "AUTOSAR 통합 자동화 플랫폼", + subtitle: "AutoSAR Integration Automation Platform", + description: `AUTOSAR 플랫폼을 기반으로 차량용 ECU 기능 개발에 필요한 모듈을 체계적으로 개발하고, 이를 하나의 환경에서 통합할 수 있는 통합 자동화 플랫폼을 구축하였습니다. + +ECU 기능 구현에 필요한 각종 소프트웨어 모듈을 기반으로 개발 및 통합 과정을 진행할 수 있도록 구성하여 차량용 소프트웨어 개발 환경의 효율성을 높였습니다. + +AUTOSAR 표준 기반의 플랫폼 환경에서 ECU 기능에 필요한 모듈을 개발하고 각각의 기능을 통합함으로써, 개별적으로 개발되는 소프트웨어 구성 요소를 체계적으로 관리하고 통합할 수 있도록 구현하였습니다. + +이를 통해 ECU 기능 개발 과정에서 발생하는 반복적인 통합 작업을 효율적으로 관리하고, AUTOSAR 기반 차량용 소프트웨어의 개발 및 통합 업무를 안정적으로 수행할 수 있는 기반을 마련하였습니다. +`, + scope: "Web · Monitoring · MES", + output: "Operation system", + image: "assets/images/si/si_01_background.jpeg", + objectImage: "assets/images/si/si_01_object.png", + objectLayout: { + x: "100%", + y: "calc(100% - 86px)", + anchorX: "-100%", + anchorY: "-100%", + maxHeight: "560px", + }, + }, + // P.39 + { + id: "patent-attorney-meeting-platform", + type: "si", + category: "개발 사례", + title: "변리사 미팅 플랫폼", + description: `국내외 특허 출원 및 해외 특허 확장을 위해 필요한 각국·각 분야의 변리사와 전문가를 연결하고, 미팅부터 업무 진행까지 원스톱으로 지원할 수 있는 위멧 변리사 미팅 플랫폼을 구축하였습니다. + +기존 이메일이나 지인 추천, 컨퍼런스 등을 통해 개별적으로 진행되던 변리사 탐색 및 미팅 과정을 플랫폼 기반으로 전환하여 보다 효율적인 업무 진행이 가능하도록 구성하였습니다. + +기계, 통신 등 특허 분야별로 전문성을 갖춘 변리사 정보를 세분화하여 제공함으로써 사용자가 필요한 분야의 전문가를 한눈에 확인하고, 업무 목적에 적합한 변리사를 쉽고 빠르게 탐색할 수 있도록 구현하였습니다. 또한 국내외 특허 업무에 필요한 전문가 연결 과정을 체계적으로 관리할 수 있도록 하여 기존의 복잡하고 비효율적인 전문가 탐색 및 커뮤니케이션 과정을 간소화하였습니다. + +이를 통해 특허 출원 및 해외 확장 과정에서 필요한 전문 인력과의 연결성을 높이고, 전문가 탐색부터 미팅까지 이어지는 업무 프로세스를 효율적으로 지원하여 특허 관련 업무의 편의성과 신속성을 향상시킬 수 있는 플랫폼 환경을 제공하였습니다. +`, + scope: "Enterprise web · Workflow", + output: "Admin · Approval flow", + image: "assets/images/si/si_02_background.jpg", + objectImage: "assets/images/si/si_02_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // P.40 + { + id: "overseas-purchasing-web-standardization", + type: "si", + category: "개발 사례", + title: "해외법인(중국&멕시코) 구매시스템 웹 표준화 전환", + subtitle: + "Overseas Subsidiary (China, Mexico) Procurement System Web Conversion Project", + description: ` 해외법인(중국, 멕시코)에서 운영 중인 레거시 FLEX 기반 구매시스템을 HTML5 기반의 웹 표준 환경으로 전환하고, 서버 및 DBMS 환경까지 Conversion을 수행하여 글로벌 구매 업무의 안정적인 운영 기반을 구축하였습니다. + +기존 FLEX 기반 시스템을 HTML5 웹 표준 기술로 전환하여 특정 기술 환경에 대한 의존성을 개선하고, 다양한 웹 환경에서 안정적으로 서비스를 이용할 수 있도록 시스템을 현대화하였습니다. 또한 기존 업무 기능과 데이터를 안정적으로 유지하면서 서버 및 DBMS 환경을 함께 Conversion하여 시스템 운영 환경의 전반적인 표준화와 효율성을 확보하였습니다. + +특히, 중국과 멕시코 해외법인에서 사용되는 구매시스템을 대상으로 웹 표준화 전환과 서버·DBMS 환경 Conversion을 성공적으로 수행함으로써 기존 레거시 시스템의 기술적 제약을 개선하고, 향후 시스템 유지보수 및 확장이 용이한 웹 기반 환경을 마련하였습니다. + +이를 통해 해외법인의 구매 업무 연속성을 확보하고 글로벌 시스템 운영의 안정성과 관리 효율성을 향상시켰습니다. +`, + scope: "Enterprise · Media · CMS", + output: "CMS · Player", + image: "assets/images/si/si_03_background.png", + objectImage: "assets/images/si/si_03_object.png", + objectLayout: { + x: "100%", + y: "calc(100% - 86px)", + anchorX: "-100%", + anchorY: "-100%", + maxHeight: "560px", + }, + }, + // P.41 + { + id: "photocard-kiosk-management", + type: "si", + category: "개발 사례", + title: "포토카드 키오스크 및 관리 시스템", + subtitle: "Photocard Kiosk and Management System", + description: `공연장·전시회·팝업스토어 등 다양한 현장에서 방문객이 별도의 지원 없이 이미지 선택부터 카드 편집, 결제, 포토카드 출력까지 전 과정을 이용할 수 있는 무인 포토카드 제작 서비스입니다. + +현장 키오스크와 결제 장치, 포토 프린터를 연동하여 편리하고 안정적인 무인 제작 환경을 제공하며, 웹 기반 관리자 시스템을 통해 콘텐츠와 출력 데이터를 통합 관리할 수 있게 개발하였습니다. + +특히 관리 시스템을 현장에 맞춰 개발하여 출력 이력과 데이터 관리가 원활하게 이루어질 수 있도록 하였습니다. +`, + scope: "App · Backend · Admin", + output: "iOS/Android · API", + image: "assets/images/si/si_04_background.png", + objectImage: "assets/images/si/si_04_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // P.42 + { + id: "ai-medical-beauty-platform", + type: "si", + category: "개발 사례", + title: "AI 기반 메디컬 뷰티 플랫폼", + subtitle: "AI Based Medical Beauty Service Platform", + description: `생성형 인공지능을 활용하여 사용자의 관심과 요구에 맞는 병원 및 시술 정보를 추천하고, 병원 선택부터 예약과 결제까지 하나의 플랫폼에서 진행할 수 있는 AI 기반 메디컬 뷰티 플랫폼을 구축하였습니다. + +사용자 맞춤형 추천 기능을 통해 개인의 관심 분야와 조건에 적합한 성형외과 및 시술 정보를 제공하고, 위치정보를 기반으로 사용자 인근의 성형외과 정보를 확인할 수 있도록 구성하여 병원 탐색의 편의성을 높였습니다. 또한 성형외과 전용 시술정보와 예약관리 기능을 제공하고, 고객 피드백을 체계적으로 관리할 수 있도록 하여 병원과 고객 간의 효율적인 소통을 지원하였습니다. + +특히, 병원 및 시술 정보 탐색부터 예약, 결제까지의 과정을 하나의 서비스로 연결한 원스톱 예약·결제 시스템을 구현하여 사용자의 서비스 이용 절차를 간소화하였습니다. + +이를 통해 생성형 AI 기반의 개인화된 정보 추천과 위치 기반 병원 검색, 시술정보 및 예약·결제 서비스를 통합하여 메디컬 뷰티 분야의 사용자 편의성과 서비스 접근성을 높이고, 병원 운영 및 고객관리의 효율성을 향상시킬 수 있는 플랫폼 환경을 제공하였습니다. +`, + scope: "Field app · Checklist", + output: "Mobile · Admin console", + image: "assets/images/si/si_05_background.png", + }, + // P.43 + { + id: "child-safety-platform", + type: "si", + category: "개발 사례", + title: "자녀 안심 플랫폼", + subtitle: "Children Security Zone Management Platform", + description: `자녀의 스마트폰 사용 환경을 안전하게 관리하고 보호자가 원격으로 자녀의 상태를 관리할 수 있도록 스마트폰 제어 및 위치 기반 기능을 통합한 자녀 안심 플랫폼을 구축하였습니다. + +스마트폰 사용시간 제어와 원격 관리 기능을 제공하여 보호자가 자녀의 스마트폰 이용 환경을 효율적으로 관리할 수 있도록 구성하였습니다. + +GPS 기반의 자녀 안심존 관리 기능을 통해 지정된 안전 구역의 설정 및 자녀의 출입 여부를 확인할 수 있도록 하고, 출입 상황을 보호자에게 통지하여 자녀의 위치 및 이동 상황을 보다 편리하게 확인할 수 있도록 구현하였습니다. 또한 스마트폰 카메라 장치 제어 기술을 적용하여 불법적인 촬영 및 몸캠 피해를 예방할 수 있는 기능을 제공하고, 스마트폰 화면 제어 기술을 기반으로 사이버 폭력 및 음란 문자와 같은 유해 콘텐츠를 감지할 수 있도록 구성하였습니다. + +자이로센서 기술을 활용하여 자녀가 보행 중 스마트폰을 사용하는 상황을 감지하고 스마트폰 잠금을 활성화하는 스몸비 방지 기능을 구현하였으며, Android Framework 제어 기술을 적용하여 스마트폰 권한 및 애플리케이션을 원격으로 관리할 수 있도록 하였습니다. + +이를 통해 스마트폰 사용 관리, 위치 및 출입 관리, 유해 콘텐츠 대응, 보행 안전, 애플리케이션 관리 등 자녀 보호에 필요한 다양한 기능을 하나의 플랫폼으로 통합하여 보호자의 관리 편의성과 자녀의 스마트폰 이용 안전성을 향상시켰습니다. +`, + scope: "Admin · RBAC · Audit", + output: "Console · Log", + image: "assets/images/si/si_06_background.png", + }, + // P.44 + { + id: "room-management-platform", + type: "si", + category: "개발 사례", + title: "룸 매니징 플랫폼", + subtitle: "Hotel Room Managing Service Platform", + description: `호텔 객실에서 제공되는 다양한 콘텐츠와 객실 제어, 고객 편의 서비스를 하나의 플랫폼으로 통합하여 호텔 운영의 효율성과 고객 서비스 품질을 향상시킬 수 있는 룸 매니징 플랫폼을 구축하였습니다. + +통합 리모컨을 통해 실시간 TV와 OTT 서비스를 편리하게 이용할 수 있도록 하고, 조명 및 객실 제어 기능을 연계하여 고객이 객실 내 주요 기능을 손쉽게 관리할 수 있도록 구성하였습니다. + +객실 초기 화면에 호텔 공지 및 안내사항을 제공하여 고객이 필요한 정보를 사전에 확인할 수 있도록 함으로써 불필요한 문의를 줄이고, 호텔 소개와 시설 안내, 예약 서비스 등을 통해 호텔 이용에 필요한 정보를 편리하게 제공하였습니다. 또한 대실 및 숙박 연장, 셀프 체크아웃 기능을 지원하여 프런트 업무를 간소화하고 고객이 원하는 시간에 직접 서비스를 이용할 수 있도록 구현하였습니다. + +고객의 편의와 만족도를 높일 수 있도록 다양한 상품 및 룸 서비스를 제공하고, 비대면 결제와 비대면 배송 시스템을 연계하여 객실에서 주문부터 결제 및 상품 수령까지 편리하게 이용할 수 있도록 구성하였습니다. + +이를 통해 객실 제어부터 콘텐츠 이용, 호텔 정보 확인, 예약 및 결제, 룸 서비스까지 고객에게 필요한 서비스를 하나의 플랫폼에서 제공하고, 동시에 비대면 업무와 부가 서비스 판매를 통해 호텔 운영 효율성과 고객 편의성, 수익성을 함께 향상시킬 수 있는 통합 객실 서비스 환경을 구현하였습니다. +`, + scope: "API · Cloud · Auth", + output: "Backend · Docs", + image: "assets/images/si/si_07_background.png", + objectImage: "assets/images/si/si_07_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, + // P.45 + { + id: "smart-tracking-system", + type: "si", + category: "개발 사례", + title: "스마트 트래킹 시스템", + subtitle: "Smart Location Tracking System", + description: `스마트폰과 귀중품의 분실을 예방하고 분실 상황에서도 쉽고 빠르게 위치를 확인할 수 있도록 스마트폰과 스마트 트래커를 연계한 스마트 트래킹 시스템을 구축하였습니다. + +스마트폰과 ‘I’m Here’가 일정 거리 이상 멀어지는 상황을 감지하여 양쪽에서 알림을 제공함으로써 스마트폰뿐만 아니라 지갑, 가방, 자동차 키 등 휴대가 잦은 귀중품의 분실을 사전에 방지할 수 있도록 구성하였습니다. + +귀중품을 분실한 경우에는 스마트폰의 Smart[Home] App과 연계하여 분실 위치를 지도에서 확인할 수 있도록 하였으며, 스마트폰과 스마트 트래커가 가까운 위치에 있는 경우에는 트래커 버튼을 연속으로 두 번 눌러 스마트폰에서 알림음이 울리도록 하여 주변에서 스마트폰을 쉽게 찾을 수 있도록 구현하였습니다. + +반대로 귀중품의 경우에도 Smart[Home] App에서 해당 트래커를 선택하는 것만으로 위치를 확인하고 찾을 수 있도록 구성하여 양방향 탐색 기능을 제공합니다. 또한 공항 수하물 수취 과정에서는 스마트폰과 수하물 간의 거리가 가까워지는 상황을 감지하여 스마트폰에서 알림음을 제공함으로써 수하물 도착 여부를 보다 편리하게 확인할 수 있도록 하였습니다. + +이를 통해 거리 기반 알림, 위치정보, 스마트폰 연계 기능을 활용하여 일상생활 속 스마트폰 및 귀중품의 분실을 예방하고, 필요한 경우 신속하게 위치를 확인할 수 있는 사용자 중심의 스마트 트래킹 환경을 구현하였습니다. +`, + scope: "API · Cloud · Auth", + output: "Backend · Docs", + image: "assets/images/si/si_08_background.png", + objectImage: "assets/images/si/si_08_object.png", + objectLayout: { + x: "50%", + y: "50%", + anchorX: "-50%", + anchorY: "-50%", + maxHeight: "560px", + }, + }, +]; diff --git a/js/main.js b/js/main.js new file mode 100644 index 0000000..1c42be7 --- /dev/null +++ b/js/main.js @@ -0,0 +1,1051 @@ +(function () { + // 공통: 스크롤에 따른 헤더 표시와 모바일 메뉴 열기/닫기. + const header = document.querySelector("[data-header]"); + const toggle = document.querySelector("[data-menu-toggle]"); + const mobileMenu = document.querySelector("[data-mobile-menu]"); + + function updateHeader() { + if (!header) return; + header.classList.toggle("is-scrolled", window.scrollY > 20); + } + + updateHeader(); + window.addEventListener("scroll", updateHeader, { passive: true }); + + if (toggle && mobileMenu) { + mobileMenu.id = "mobile-navigation"; + mobileMenu.inert = true; + toggle.setAttribute("aria-controls", mobileMenu.id); + toggle.setAttribute("aria-expanded", "false"); + const menuLinks = [...mobileMenu.querySelectorAll("a")]; + const menuLabels = ["Company", "Capabilities", "ESG", "Contact"]; + menuLinks.forEach((link, index) => { + const title = document.createElement("span"); + title.className = "mobile-menu-title"; + title.textContent = link.textContent; + const label = document.createElement("span"); + label.className = "mobile-menu-label"; + label.textContent = menuLabels[index]; + const arrow = document.createElement("img"); + arrow.src = "assets/icons/chevron_forward.svg"; + arrow.alt = ""; + link.replaceChildren(label, title, arrow); + link.style.setProperty("--menu-index", index); + if (new URL(link.href).pathname === location.pathname) link.setAttribute("aria-current", "page"); + }); + const signature = document.createElement("div"); + signature.className = "mobile-menu-signature"; + signature.innerHTML = 'MOBIPIN TECHNOLOGY053-214-0592'; + mobileMenu.appendChild(signature); + const backgroundElements = [...document.querySelectorAll("main, .site-footer")]; + const previousInert = new Map(); + function setMenuOpen(isOpen, restoreFocus = false) { + mobileMenu.classList.toggle("is-open", isOpen); + document.body.classList.toggle("mobile-navigation-open", isOpen); + toggle.classList.toggle("is-open", isOpen); + mobileMenu.inert = !isOpen; + toggle.setAttribute("aria-label", isOpen ? "메뉴 닫기" : "메뉴 열기"); + toggle.setAttribute("aria-expanded", String(isOpen)); + backgroundElements.forEach((element) => { + if (isOpen) { + if (!previousInert.has(element)) previousInert.set(element, element.inert); + element.inert = true; + } else if (previousInert.has(element)) { + element.inert = previousInert.get(element); + previousInert.delete(element); + } + }); + if (restoreFocus) toggle.focus(); + } + toggle.addEventListener("click", () => setMenuOpen(!mobileMenu.classList.contains("is-open"))); + mobileMenu.addEventListener("click", (event) => { + if (event.target.closest("a")) setMenuOpen(false); + }); + document.addEventListener("keydown", (event) => { + if (!mobileMenu.classList.contains("is-open")) return; + if (event.key === "Escape") { + event.preventDefault(); + setMenuOpen(false, true); + } else if (event.key === "Tab") { + const focusable = [toggle, ...mobileMenu.querySelectorAll("a")]; + const current = focusable.indexOf(document.activeElement); + event.preventDefault(); + focusable[(current + (event.shiftKey ? -1 : 1) + focusable.length) % focusable.length].focus(); + } + }); + window.matchMedia("(min-width: 861px)").addEventListener("change", (event) => { + if (event.matches) setMenuOpen(false); + }); + } + + // 홈·회사소개·ESG: 데스크톱 섹션 이동, 트랙패드 관성 처리, 방향키 조작. + if (["home-body", "about-body", "esg-body"].some((name) => document.body.classList.contains(name))) { + const pageMode = window.matchMedia("(min-width: 861px) and (min-height: 700px)"); + const sections = Array.from(document.querySelectorAll("main > section, .site-footer")); + const indicatorSections = sections.filter((section) => section.dataset.pageTitle); + const pageIndicator = createPageIndicator(); + let transitionUntil = 0; + let lastWheelAt = 0; + let wheelDistance = 0; + let gestureConsumed = false; + let previousWheelDelta = 0; + const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)"); + + function pageStops() { + const maxScroll = Math.max(0, document.documentElement.scrollHeight - window.innerHeight); + const headerHeight = header ? header.getBoundingClientRect().height : 0; + return [...new Set(sections.map((section) => Math.round(Math.max(0, + Math.min(maxScroll, section.getBoundingClientRect().top + window.scrollY - headerHeight) + ))))]; + } + + function sectionStop(section) { + const maxScroll = Math.max(0, document.documentElement.scrollHeight - window.innerHeight); + const headerHeight = header ? header.getBoundingClientRect().height : 0; + return Math.round(Math.max(0, + Math.min(maxScroll, section.getBoundingClientRect().top + window.scrollY - headerHeight) + )); + } + + function usesPageNavigation() { + if (!pageMode.matches) return false; + if (document.querySelector(".site-dialog[open]")) return false; + if (mobileMenu && mobileMenu.classList.contains("is-open")) return; + // Long sections retain native scrolling so their content stays reachable. + const activeSection = sections.find((section) => { + const rect = section.getBoundingClientRect(); + return rect.top <= 73 && rect.bottom > 73; + }); + if (activeSection && activeSection.offsetHeight > window.innerHeight && + !activeSection.classList.contains("home-hero")) return false; + return true; + } + + function moveHomePage(direction) { + const now = performance.now(); + if (now < transitionUntil) return; + const stops = pageStops(); + const target = direction > 0 + ? stops.find((stop) => stop > window.scrollY + 4) + : [...stops].reverse().find((stop) => stop < window.scrollY - 4); + if (target === undefined) return; + transitionUntil = now + 900; + window.scrollTo({ top: target, behavior: reducedMotion.matches ? "instant" : "smooth" }); + } + + function createPageIndicator() { + if (!["home-body", "about-body"].some((name) => document.body.classList.contains(name))) return null; + if (indicatorSections.length < 2) return null; + const nav = document.createElement("nav"); + nav.className = "page-dots"; + nav.setAttribute("aria-label", "페이지 섹션"); + indicatorSections.forEach((section, index) => { + const title = section.dataset.pageTitle; + const button = document.createElement("button"); + button.type = "button"; + button.className = "page-dot"; + button.dataset.index = String(index); + button.setAttribute("aria-label", `${title} 섹션으로 이동`); + button.innerHTML = `${title}`; + button.addEventListener("click", () => { + transitionUntil = performance.now() + 900; + window.scrollTo({ top: sectionStop(section), behavior: reducedMotion.matches ? "instant" : "smooth" }); + }); + nav.appendChild(button); + }); + document.body.appendChild(nav); + return nav; + } + + function updatePageIndicator() { + if (!pageIndicator) return; + const viewportLine = (header ? header.getBoundingClientRect().height : 0) + Math.min(120, window.innerHeight * .24); + let activeIndex = 0; + indicatorSections.forEach((section, index) => { + const rect = section.getBoundingClientRect(); + if (rect.top <= viewportLine && rect.bottom > viewportLine) activeIndex = index; + }); + pageIndicator.querySelectorAll(".page-dot").forEach((button, index) => { + const isActive = index === activeIndex; + button.classList.toggle("is-active", isActive); + if (isActive) button.setAttribute("aria-current", "true"); + else button.removeAttribute("aria-current"); + }); + } + + function canScrollPolicy(target, direction) { + const panel = target.closest(".esg-policy-panel"); + if (!panel || panel.hidden) return false; + const remaining = panel.scrollHeight - panel.clientHeight - panel.scrollTop; + return direction > 0 ? remaining > 2 : panel.scrollTop > 2; + } + + window.addEventListener("wheel", (event) => { + if (!usesPageNavigation() || event.ctrlKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) return; + if (canScrollPolicy(event.target, Math.sign(event.deltaY))) { + wheelDistance = 0; + gestureConsumed = false; + previousWheelDelta = 0; + return; + } + event.preventDefault(); + const now = performance.now(); + const delta = event.deltaY * (event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? window.innerHeight : 1); + if (!delta) return; + const directionChanged = previousWheelDelta && Math.sign(delta) !== Math.sign(previousWheelDelta); + const renewedGesture = Math.abs(delta) >= 4 && Math.abs(delta) > Math.abs(previousWheelDelta) * 1.8; + // Momentum can overlap a new swipe without a gap between wheel events. + if (now - lastWheelAt > 120 || directionChanged || + (gestureConsumed && now >= transitionUntil && renewedGesture)) { + wheelDistance = 0; + gestureConsumed = false; + } + lastWheelAt = now; + previousWheelDelta = delta; + if (now < transitionUntil || gestureConsumed) return; + if (Math.sign(delta) !== Math.sign(wheelDistance)) wheelDistance = 0; + wheelDistance += delta; + if (Math.abs(wheelDistance) < 24) return; + gestureConsumed = true; + moveHomePage(Math.sign(wheelDistance)); + }, { passive: false }); + + window.addEventListener("keydown", (event) => { + if (!usesPageNavigation() || !["ArrowUp", "ArrowDown"].includes(event.key)) return; + if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || + event.target.closest("input, textarea, select, [contenteditable], [role='textbox'], [role='tab']")) return; + if (canScrollPolicy(event.target, event.key === "ArrowDown" ? 1 : -1)) return; + event.preventDefault(); + if (!event.repeat) moveHomePage(event.key === "ArrowDown" ? 1 : -1); + }); + + window.addEventListener("scroll", updatePageIndicator, { passive: true }); + window.addEventListener("resize", updatePageIndicator); + pageMode.addEventListener("change", updatePageIndicator); + updatePageIndicator(); + } + + // 공통: 푸터와 문의 폼에서 여는 개인정보 처리방침·사이트맵 모달. + const modalContent = { + privacy: { + title: "개인정보 처리방침", + body: `

주식회사 모비핀테크놀러지는 문의 과정에서 수집되는 개인정보의 처리 기준과 보호에 관한 사항을 다음과 같이 안내합니다.

+

1. 개인정보 수집 및 이용 목적

+

주식회사 모비핀테크놀러지는 프로젝트 문의 확인, 상담 및 답변을 위해 문의자가 제공한 정보를 이용합니다.

+

2. 수집하는 항목

+

이름, 회사명, 이메일, 연락처, 문의 분야 및 문의 내용. 파일을 첨부한 경우 해당 파일에 포함된 정보가 함께 전달됩니다.

+

3. 보유 및 이용 기간

+

수집된 개인정보는 문의 처리 완료 후 1년간 보관하며, 보유 기간이 지나면 지체 없이 파기합니다.

+

4. 정보 제공 및 처리 위탁

+

제공된 정보는 문의 응대 목적으로 사용합니다. 외부 서비스에 처리를 위탁하는 경우 해당 서비스와 처리 범위를 운영 방침에 명시합니다.

+

5. 동의 거부 및 정보 확인

+

개인정보 수집 및 이용에 동의하지 않을 수 있습니다. 동의하지 않으면 온라인 문의를 전송할 수 없으며, 고객센터로 직접 연락할 수 있습니다. 제공한 정보의 확인, 수정, 삭제 요청도 고객센터로 문의할 수 있습니다.

+

6. 개인정보 관련 문의

+

주식회사 모비핀테크놀러지 · 고객센터 053-214-0592
평일 09:00 ~ 18:00

`, + }, + sitemap: { + title: "사이트맵", + body: ``, + }, + }; + Object.entries(modalContent).forEach(([key, content]) => { + const dialog = document.createElement("dialog"); + dialog.className = "site-dialog"; + dialog.id = `site-${key}`; + dialog.setAttribute("aria-labelledby", `${dialog.id}-title`); + dialog.innerHTML = ` +
+

${content.title}

+ +
+
${content.body}
`; + document.body.appendChild(dialog); + dialog.querySelector(".dialog-close").addEventListener("click", () => dialog.close()); + dialog.addEventListener("click", (event) => { + const rect = dialog.getBoundingClientRect(); + const clickedOutside = event.target === dialog && ( + event.clientX < rect.left || event.clientX > rect.right || + event.clientY < rect.top || event.clientY > rect.bottom + ); + if (clickedOutside) dialog.close(); + }); + dialog.querySelectorAll(".sitemap-groups a").forEach((link) => { + link.addEventListener("click", () => dialog.close()); + }); + dialog.addEventListener("close", () => document.documentElement.classList.remove("has-site-dialog")); + document.querySelectorAll(`[data-site-modal="${key}"]`).forEach((trigger) => { + trigger.setAttribute("aria-haspopup", "dialog"); + trigger.setAttribute("aria-controls", dialog.id); + trigger.addEventListener("click", () => { + dialog.showModal(); + dialog.querySelector(".site-dialog-content").scrollTop = 0; + document.documentElement.classList.add("has-site-dialog"); + }); + }); + }); + + // 문의하기: PocketBase에 문의와 첨부파일을 저장. + const form = document.querySelector("[data-contact-form]"); + if (form) { + const consent = form.querySelector("[data-privacy-consent]"); + const submitButton = form.querySelector("[data-contact-submit]"); + const note = form.querySelector("[data-form-note]"); + const fileInput = form.querySelector("[data-contact-files]"); + const progressOverlay = document.querySelector("[data-contact-progress]"); + const progressBar = progressOverlay?.querySelector("[data-contact-progressbar]"); + const progressFill = progressOverlay?.querySelector("[data-contact-progress-fill]"); + const progressLabel = progressOverlay?.querySelector("[data-contact-progress-label]"); + const progressTitle = progressOverlay?.querySelector("[data-contact-progress-title]"); + const submitLabel = submitButton?.textContent || "문의 전송"; + const endpoint = "https://api.sori.studio/api/collections/mobipintech_website_inquiries/records"; + const privacyVersion = "2026-09-21"; + const maxAttachmentBytes = 100 * 1024 * 1024; + const maxAttachmentCount = 3; + const pageRegions = Array.from(document.querySelectorAll("header, main, footer")); + const previousInert = new Map(); + let isSubmitting = false; + + function updateConsent() { + if (submitButton) submitButton.disabled = isSubmitting || !consent || !consent.checked; + } + + function showFormNote(message, state) { + if (!note) return; + note.hidden = false; + note.textContent = message; + note.classList.toggle("is-success", state === "success"); + note.classList.toggle("is-error", state === "error"); + } + + function validateAttachments(showError = false) { + if (!fileInput) return true; + const files = Array.from(fileInput.files || []); + const totalBytes = files.reduce((sum, file) => sum + file.size, 0); + const countValid = files.length <= maxAttachmentCount; + const sizeValid = totalBytes <= maxAttachmentBytes; + const validationMessage = !countValid + ? "첨부파일은 최대 3개까지 선택할 수 있습니다." + : !sizeValid ? "첨부파일 전체 용량은 100MB 이하여야 합니다." : ""; + const isValid = countValid && sizeValid; + fileInput.setCustomValidity(validationMessage); + if (!isValid && showError) { + showFormNote(validationMessage, "error"); + fileInput.reportValidity(); + } + return isValid; + } + + function setPageSubmitting(submitting) { + document.body.classList.toggle("is-contact-submitting", submitting); + pageRegions.forEach((region) => { + if (submitting) { + previousInert.set(region, region.inert); + region.inert = true; + } else if (previousInert.has(region)) { + region.inert = previousInert.get(region); + previousInert.delete(region); + } + }); + if (progressOverlay) { + progressOverlay.hidden = !submitting; + if (submitting) progressOverlay.focus(); + } + } + + function updateProgress(percent, title = "문의 전송 중") { + const value = Math.max(0, Math.min(100, Math.round(percent))); + if (progressFill) progressFill.style.width = `${value}%`; + if (progressLabel) progressLabel.textContent = `${value}%`; + if (progressTitle) progressTitle.textContent = title; + if (progressBar) progressBar.setAttribute("aria-valuenow", String(value)); + } + + function uploadInquiry(formData) { + return new Promise((resolve, reject) => { + const request = new XMLHttpRequest(); + request.open("POST", endpoint); + request.setRequestHeader("Accept", "application/json"); + request.upload.addEventListener("progress", (event) => { + if (!event.lengthComputable) return; + const percent = Math.min(95, (event.loaded / event.total) * 95); + updateProgress(percent, "문의 전송 중"); + }); + request.upload.addEventListener("load", () => updateProgress(95, "접수 처리 중")); + request.addEventListener("load", () => { + let response = null; + try { + response = JSON.parse(request.responseText); + } catch (_) { + // PocketBase가 JSON이 아닌 응답을 반환하면 상태 코드로 처리합니다. + } + if (request.status >= 200 && request.status < 300) { + resolve(response); + return; + } + const fieldMessage = response?.data?.attachments?.message; + const error = new Error(fieldMessage || response?.message || `문의 저장 실패 (${request.status})`); + error.isAttachmentError = Boolean(fieldMessage); + reject(error); + }); + request.addEventListener("error", () => reject(new Error("문의 서버에 연결할 수 없습니다."))); + request.addEventListener("abort", () => reject(new Error("문의 전송이 중단되었습니다."))); + request.send(formData); + }); + } + + if (consent) consent.addEventListener("change", updateConsent); + if (fileInput) fileInput.addEventListener("change", () => validateAttachments(true)); + form.addEventListener("reset", () => window.setTimeout(updateConsent, 0)); + window.addEventListener("beforeunload", (event) => { + if (!isSubmitting) return; + event.preventDefault(); + event.returnValue = ""; + }); + updateConsent(); + form.addEventListener("submit", async (event) => { + event.preventDefault(); + if (isSubmitting || !consent || !consent.checked || !validateAttachments(true) || !form.reportValidity()) return; + + isSubmitting = true; + updateConsent(); + if (submitButton) submitButton.textContent = "전송 중..."; + if (note) note.hidden = true; + updateProgress(0); + setPageSubmitting(true); + + const formData = new FormData(form); + formData.set("privacyConsent", "true"); + formData.set("privacyVersion", privacyVersion); + formData.set("status", "new"); + + try { + await uploadInquiry(formData); + updateProgress(100, "접수 완료"); + await new Promise((resolve) => window.setTimeout(resolve, 350)); + form.reset(); + showFormNote("문의가 정상적으로 접수되었습니다. 담당자가 확인 후 연락드리겠습니다.", "success"); + } catch (error) { + console.error("Contact form submission failed:", error); + const message = error.isAttachmentError + ? "첨부파일이 서버의 허용 용량이나 형식 제한을 초과했습니다. 파일을 확인해 주세요." + : "문의 전송에 실패했습니다. 잠시 후 다시 시도하거나 고객센터 053-214-0592로 연락해 주세요."; + showFormNote(message, "error"); + } finally { + isSubmitting = false; + setPageSubmitting(false); + if (submitButton) submitButton.textContent = submitLabel; + updateConsent(); + } + }); + } + + // ESG: 문서 선택, 탭 방향키 조작, URL 해시와 선택 상태 동기화. + const policyTabs = Array.from(document.querySelectorAll("[data-esg-tab]")); + if (policyTabs.length) { + const workspace = document.querySelector(".esg-workspace"); + const tabList = document.querySelector(".esg-policy-tabs"); + function selectPolicy(id, navigate = false) { + if (!policyTabs.some((tab) => tab.dataset.esgTab === id)) return; + policyTabs.forEach((tab) => { + const selected = tab.dataset.esgTab === id; + tab.setAttribute("aria-selected", String(selected)); + tab.tabIndex = selected ? 0 : -1; + const panel = document.getElementById(tab.dataset.esgTab); + panel.hidden = !selected; + if (selected) panel.scrollTop = 0; + }); + if (navigate) workspace.scrollIntoView({ behavior: "smooth", block: "start" }); + } + policyTabs.forEach((tab, index) => { + tab.addEventListener("click", () => { + selectPolicy(tab.dataset.esgTab); + history.replaceState(null, "", `#${tab.dataset.esgTab}`); + }); + tab.addEventListener("keydown", (event) => { + let next; + if (["ArrowDown", "ArrowRight"].includes(event.key)) next = (index + 1) % policyTabs.length; + if (["ArrowUp", "ArrowLeft"].includes(event.key)) next = (index + policyTabs.length - 1) % policyTabs.length; + if (event.key === "Home") next = 0; + if (event.key === "End") next = policyTabs.length - 1; + if (next === undefined) return; + event.preventDefault(); + policyTabs[next].click(); + policyTabs[next].focus(); + }); + }); + const mobilePolicies = window.matchMedia("(max-width: 860px)"); + function updateTabOrientation() { + tabList.setAttribute("aria-orientation", mobilePolicies.matches ? "horizontal" : "vertical"); + } + updateTabOrientation(); + mobilePolicies.addEventListener("change", updateTabOrientation); + + window.addEventListener("keydown", (event) => { + if (!["ArrowLeft", "ArrowRight"].includes(event.key) || mobilePolicies.matches) return; + if (event.repeat || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || + document.querySelector(".site-dialog[open]") || + mobileMenu?.classList.contains("is-open") || + event.target.closest("input, textarea, select, [contenteditable], [role='textbox'], [data-esg-tab]")) return; + const bounds = workspace.getBoundingClientRect(); + const headerHeight = header ? header.getBoundingClientRect().height : 0; + if (bounds.bottom <= headerHeight || bounds.top >= window.innerHeight) return; + event.preventDefault(); + const current = policyTabs.findIndex((tab) => tab.getAttribute("aria-selected") === "true"); + const direction = event.key === "ArrowRight" ? 1 : -1; + policyTabs[(current + direction + policyTabs.length) % policyTabs.length].click(); + }); + + selectPolicy(location.hash.slice(1)); + window.addEventListener("hashchange", () => selectPolicy(location.hash.slice(1), true)); + } + + // 기술 역량: capabilities-data.js의 프로젝트로 슬라이드와 목록을 구성. + const projects = window.CAPABILITY_PROJECTS || []; + const grid = document.querySelector("[data-project-navigation]"); + const featureBg = document.querySelector("[data-feature-bg]"); + const featureObject = document.querySelector("[data-feature-object]"); + const featureObjectSecondary = document.querySelector("[data-feature-object-secondary]"); + const featureContent = document.querySelector(".feature-content"); + const featureTable = document.querySelector("[data-feature-table]"); + const featureCategory = document.querySelector("[data-feature-category]"); + const featureTitle = document.querySelector("[data-feature-title]"); + const featureSubtitle = document.querySelector("[data-feature-subtitle]"); + const featureDescription = document.querySelector("[data-feature-description]"); + const filterButtons = document.querySelectorAll("[data-filter]"); + const autoplayButtons = document.querySelectorAll("[data-autoplay-toggle]"); + const prevButtons = document.querySelectorAll("[data-slide-prev]"); + const nextButtons = document.querySelectorAll("[data-slide-next]"); + const slideCounter = document.querySelector("[data-slide-counter]"); + const capabilitiesWorkbench = document.querySelector(".capabilities-workbench"); + + if (!grid || !projects.length) return; + + const labels = { + automotive: "Automotive", + robotics: "Robotics", + solution: "Solution", + si: "SI", + certifications: "Patents" + }; + const hash = location.hash.replace("#", ""); + let currentFilter = labels[hash] ? hash : "automotive"; + let currentProjects = []; + let currentIndex = 0; + let wheelLocked = false; + let autoplayTimer = 0; + // 자동 재생 초기 상태: true = 멈춤, false = 페이지를 열면 자동 재생. + let autoplayPaused = false; + // 슬라이드 전환 간격(ms). 9000 = 9초이며 버튼의 진행 표시도 이 값을 사용. + const autoplayDelay = 9000; + + // 기술 역량: 재생/멈춤 버튼, 진행 표시, 자동 전환 타이머. + function updateAutoplayButtons(resetProgress = false) { + autoplayButtons.forEach((button) => { + const label = button.querySelector("[data-autoplay-label]"); + const icon = button.querySelector("[data-autoplay-icon]"); + const isRunning = !autoplayPaused && projects.length > 1; + if (label) label.textContent = autoplayPaused ? "재생" : "멈춤"; + if (icon) icon.src = autoplayPaused ? "assets/icons/play_arrow.svg" : "assets/icons/pause.svg"; + button.setAttribute("aria-label", autoplayPaused ? "자동 전환 재생" : "자동 전환 멈춤"); + button.setAttribute("aria-pressed", autoplayPaused ? "true" : "false"); + button.style.setProperty("--autoplay-duration", `${autoplayDelay}ms`); + button.classList.remove("is-running"); + button.classList.toggle("is-paused", autoplayPaused); + if (resetProgress) { + void button.offsetWidth; + } + button.classList.toggle("is-running", isRunning); + }); + } + + function stopAutoplay() { + window.clearTimeout(autoplayTimer); + autoplayTimer = 0; + } + + function scheduleAutoplay() { + stopAutoplay(); + updateAutoplayButtons(true); + if (autoplayPaused || projects.length < 2) return; + autoplayTimer = window.setTimeout(() => { + if (document.querySelector(".site-dialog[open]")) { + scheduleAutoplay(); + return; + } + moveFeature(1); + scheduleAutoplay(); + }, autoplayDelay); + } + + function escapeHtml(value) { + return String(value || "").replace(/[&<>"']/g, (match) => ({ + "&": "&", + "<": "<", + ">": ">", + "\"": """, + "'": "'" + }[match])); + } + + function optimizedCapabilityImage(source) { + if (!source) return ""; + return source + .replace("assets/images/", "assets/images-webp/") + .replace(/\.(?:png|jpe?g)$/i, ".webp"); + } + + let adjacentPreloadTimer = 0; + const preloadedCapabilityImages = new Map(); + function preloadProjectAssets(item) { + if (!item) return; + [item.image, item.objectImage, item.objectImageSecondary].forEach((source) => { + const optimized = optimizedCapabilityImage(source); + if (!optimized || preloadedCapabilityImages.has(optimized)) return; + const image = new Image(); + image.decoding = "async"; + image.src = optimized; + preloadedCapabilityImages.set(optimized, image); + }); + } + + function scheduleAdjacentPreload() { + window.clearTimeout(adjacentPreloadTimer); + adjacentPreloadTimer = window.setTimeout(() => { + const categories = projectCategories(); + const categoryIndex = categories.indexOf(currentFilter); + const previousCategory = categories[(categoryIndex - 1 + categories.length) % categories.length]; + const nextCategory = categories[(categoryIndex + 1) % categories.length]; + const previousProjects = projects.filter((item) => item.type === previousCategory); + const previous = currentProjects[currentIndex - 1] || previousProjects[previousProjects.length - 1]; + const next = currentProjects[currentIndex + 1] || + projects.find((item) => item.type === nextCategory); + preloadProjectAssets(previous); + preloadProjectAssets(next); + }, 1000); + } + + // 기술 역량: 전장 기타 프로젝트 표. + function renderFeatureTable(item) { + if (!featureTable) return; + const rows = item.tableRows || []; + featureTable.hidden = item.layout !== "table"; + if (item.layout !== "table") { + featureTable.innerHTML = ""; + return; + } + featureTable.innerHTML = ` + + + + + + + + + ${rows.map((row) => ` + + + + + `).join("")} + +
${escapeHtml(item.tableHeaders?.[0] || "사업명")}${escapeHtml(item.tableHeaders?.[1] || "사업기간")}
${escapeHtml(row[0])}${escapeHtml(row[1])}
+ `; + } + + // 기술 역량: 모바일 특허증 본문과 오브젝트의 겹침 방지·등장/퇴장 처리. + const objectTransitions = new WeakMap(); + const certificateGallery = document.createElement("div"); + certificateGallery.className = "mobile-certificate-gallery"; + certificateGallery.hidden = true; + if (featureContent) featureContent.append(certificateGallery); + + function fitFeatureObjects() { + if (!capabilitiesWorkbench || !featureContent) return; + const stage = capabilitiesWorkbench.querySelector(".workbench-stage"); + if (!stage) return; + const desktop = !window.matchMedia("(max-width: 860px)").matches; + const hasDescription = !capabilitiesWorkbench.classList.contains("is-table-slide") && + !capabilitiesWorkbench.classList.contains("is-certification-slide"); + const stageBounds = stage.getBoundingClientRect(); + if (desktop && capabilitiesWorkbench.classList.contains("is-certification-slide") && featureTitle) { + const titleBottom = featureTitle.getBoundingClientRect().bottom - stageBounds.top; + capabilitiesWorkbench.style.setProperty("--certificate-top", `${titleBottom + 24}px`); + } + const contentRight = featureContent.getBoundingClientRect().right + 32; + [featureObject, featureObjectSecondary].forEach((element) => { + if (!element) return; + element.style.removeProperty("width"); + element.style.removeProperty("height"); + element.style.removeProperty("--object-fit-x"); + if (!desktop || !hasDescription || !element.getAttribute("src")) return; + const style = window.getComputedStyle(element); + const width = parseFloat(style.width); + const height = parseFloat(style.height); + const available = Math.max(0, stageBounds.right - contentRight); + if (!width || !height) return; + // Fit the actual image ratio, not the potentially letterboxed CSS rectangle. + const naturalWidth = element.naturalWidth; + const naturalHeight = element.naturalHeight; + if (!naturalWidth || !naturalHeight) return; + const ratio = Math.min(width / naturalWidth, height / naturalHeight, available / naturalWidth); + element.style.width = `${naturalWidth * ratio}px`; + element.style.height = `${naturalHeight * ratio}px`; + const bounds = element.getBoundingClientRect(); + const motionX = parseFloat(window.getComputedStyle(element).translate) || 0; + const settledLeft = bounds.left - motionX; + element.style.setProperty("--object-fit-x", `${Math.max(0, contentRight - settledLeft)}px`); + }); + } + + if (capabilitiesWorkbench && featureContent) { + const objectFitObserver = new ResizeObserver(fitFeatureObjects); + objectFitObserver.observe(featureContent); + objectFitObserver.observe(capabilitiesWorkbench); + window.addEventListener("resize", fitFeatureObjects); + [featureObject, featureObjectSecondary].forEach((element) => { + if (element) element.addEventListener("load", fitFeatureObjects); + }); + } + + function setFeature(item, index = currentIndex) { + if (!item) return; + currentIndex = index; + if (capabilitiesWorkbench) { + capabilitiesWorkbench.classList.toggle("is-table-slide", item.layout === "table"); + capabilitiesWorkbench.classList.toggle("is-certification-slide", item.layout === "certifications"); + } + if (featureContent) { + featureContent.hidden = item.layout === "table"; + featureContent.scrollTop = 0; + } + certificateGallery.hidden = item.layout !== "certifications"; + certificateGallery.replaceChildren(); + if (item.layout === "certifications") { + [item.objectImage, item.objectImageSecondary].filter(Boolean).forEach((src, index) => { + const image = document.createElement("img"); + image.src = optimizedCapabilityImage(src); + image.alt = `${item.title} ${index + 1}`; + certificateGallery.append(image); + }); + } + renderFeatureTable(item); + if (featureTable) { + featureTable.scrollTop = 0; + featureTable.scrollLeft = 0; + } + if (featureBg) { + const background = optimizedCapabilityImage(item.image); + featureBg.style.backgroundImage = background ? `url("${background}")` : "none"; + } + const setFeatureObject = async (element, image, placement, layout, motion) => { + if (!element) return; + const token = {}; + objectTransitions.set(element, token); + const wasVisible = element.classList.contains("is-visible"); + element.classList.remove("is-visible"); + const reducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches; + const preload = new Image(); + if (image) preload.src = image; + await Promise.all([ + new Promise((resolve) => window.setTimeout(resolve, wasVisible && !reducedMotion ? 280 : 0)), + image ? preload.decode().catch(() => {}) : Promise.resolve(), + ]); + if (objectTransitions.get(element) !== token) return; + // Change placement only while hidden, so anchors never become motion paths. + element.className = element === featureObject + ? "feature-object is-repositioning" + : "feature-object feature-object-secondary is-repositioning"; + element.removeAttribute("style"); + if (!image) { + element.removeAttribute("src"); + return; + } + element.src = image; + if (motion === "bottom") element.classList.add("is-motion-bottom"); + if (placement) element.classList.add(`is-${placement}`); + if (layout) { + element.classList.add("is-custom-layout"); + const properties = { + x: "--object-x", y: "--object-y", + anchorX: "--object-anchor-x", anchorY: "--object-anchor-y", + width: "--object-width", height: "--object-height", + maxWidth: "--object-max-width", maxHeight: "--object-max-height", + }; + Object.entries(properties).forEach(([key, property]) => { + if (layout[key] !== undefined) element.style.setProperty(property, layout[key]); + }); + } + fitFeatureObjects(); + void element.offsetWidth; + element.classList.remove("is-repositioning"); + window.requestAnimationFrame(() => { + if (objectTransitions.get(element) === token) element.classList.add("is-visible"); + }); + }; + setFeatureObject( + featureObject, + optimizedCapabilityImage(item.objectImage), + item.objectPlacement, + item.objectLayout, + item.objectMotion, + ); + setFeatureObject( + featureObjectSecondary, + optimizedCapabilityImage(item.objectImageSecondary), + item.objectPlacementSecondary, + item.objectLayoutSecondary, + item.objectMotionSecondary, + ); + if (featureCategory) featureCategory.textContent = item.category; + if (featureTitle) featureTitle.textContent = item.title; + if (featureSubtitle) featureSubtitle.textContent = item.subtitle || item.scope || ""; + if (featureDescription) featureDescription.textContent = item.description; + if (slideCounter) { + slideCounter.textContent = `${String(currentIndex + 1).padStart(2, "0")} / ${String(currentProjects.length).padStart(2, "0")}`; + } + + grid.querySelectorAll(".project-link").forEach((button) => { + button.classList.toggle("is-active", button.dataset.id === item.id); + button.setAttribute("aria-current", button.dataset.id === item.id ? "true" : "false"); + }); + scheduleAdjacentPreload(); + } + + // 기술 역량: 이전/다음 이동. 카테고리 끝에서는 다음 카테고리로 순환. + function projectCategories() { + return Object.keys(labels).filter((type) => projects.some((item) => item.type === type)); + } + + function moveCategory(direction, startAtEnd = false) { + const categories = projectCategories(); + if (!categories.length) return; + const categoryIndex = categories.indexOf(currentFilter); + currentFilter = categories[(categoryIndex + direction + categories.length) % categories.length]; + history.replaceState(null, "", `#${currentFilter}`); + const lastIndex = projects.filter((item) => item.type === currentFilter).length - 1; + renderProjects(currentFilter, startAtEnd ? lastIndex : 0); + } + + function moveFeature(direction) { + if (!currentProjects.length) return; + const next = currentIndex + direction; + if (next < 0 || next >= currentProjects.length) { + moveCategory(direction, direction < 0); + return; + } + setFeature(currentProjects[next], next); + } + + function renderProjects(filter, startIndex = 0) { + const filtered = filter === "all" ? projects : projects.filter((item) => item.type === filter); + currentProjects = filtered; + currentIndex = startIndex; + grid.innerHTML = ""; + + const progress = document.createElement("div"); + progress.className = "project-progress"; + const menu = document.createElement("div"); + menu.className = "project-menu"; + const list = document.createElement("div"); + list.className = "project-menu-list"; + list.setAttribute("aria-label", `${labels[filter]} 프로젝트 목록`); + const categories = projectCategories(); + const categoryIndex = categories.indexOf(filter); + function categoryLink(direction) { + const type = categories[(categoryIndex + direction + categories.length) % categories.length]; + const button = document.createElement("button"); + button.type = "button"; + button.className = "project-category-link"; + const categoryName = `${escapeHtml(labels[type])}`; + const categoryDirection = `${direction < 0 ? "이전 분야" : "다음 분야"}`; + button.classList.add(direction < 0 ? "is-previous" : "is-next"); + button.innerHTML = direction < 0 ? categoryDirection + categoryName : categoryName + categoryDirection; + button.addEventListener("click", () => { + moveCategory(direction); + grid.classList.add("is-closed-after-click"); + }); + return button; + } + menu.append(categoryLink(-1), list, categoryLink(1)); + grid.append(progress, menu); + + filtered.forEach((item, index) => { + const thumbnail = (source, className) => source + ? `` + : ""; + const preview = `${thumbnail(item.image, "thumbnail-background")}${escapeHtml(item.title)}`; + for (const [container, className, html] of [ + [progress, "dot-button project-link", ''], + [list, "project-preview project-link", preview], + ]) { + const card = document.createElement("button"); + card.type = "button"; + card.className = className; + card.dataset.id = item.id; + card.setAttribute("aria-label", item.title); + card.innerHTML = html; + card.addEventListener("click", (event) => { + setFeature(item, index); + event.currentTarget.blur(); + grid.classList.add("is-closed-after-click"); + scheduleAutoplay(); + }); + container.appendChild(card); + } + }); + + filterButtons.forEach((button) => { + button.classList.toggle("is-active", button.dataset.filter === filter); + }); + + setFeature(filtered[startIndex], startIndex); + scheduleAutoplay(); + } + + // 기술 역량: 카테고리 선택과 URL 해시 변경. + filterButtons.forEach((button) => { + button.addEventListener("click", () => { + currentFilter = button.dataset.filter; + history.replaceState(null, "", `#${currentFilter}`); + renderProjects(currentFilter); + }); + }); + + window.addEventListener("hashchange", () => { + const filter = location.hash.slice(1); + if (labels[filter] && filter !== currentFilter) { + currentFilter = filter; + renderProjects(filter); + } + }); + + grid.addEventListener("mouseleave", () => { + grid.classList.remove("is-closed-after-click"); + }); + grid.addEventListener("focusout", (event) => { + if (!grid.contains(event.relatedTarget)) grid.classList.remove("is-closed-after-click"); + }); + // 썸네일은 목록을 처음 열 때만 로드. 목록의 휠 입력은 슬라이드로 전달하지 않음. + function loadProjectThumbnails() { + grid.querySelectorAll("[data-thumbnail-src]").forEach((image) => { + image.src = image.dataset.thumbnailSrc; + image.removeAttribute("data-thumbnail-src"); + }); + } + grid.addEventListener("mouseenter", loadProjectThumbnails); + grid.addEventListener("focusin", loadProjectThumbnails); + grid.addEventListener("wheel", (event) => event.stopPropagation(), { passive: true }); + grid.addEventListener("keydown", (event) => { + if (event.key !== "Escape") return; + grid.classList.add("is-closed-after-click"); + document.activeElement?.blur(); + }); + + window.addEventListener("keydown", (event) => { + if (!["ArrowUp", "ArrowDown", "ArrowLeft", "ArrowRight"].includes(event.key) || + window.matchMedia("(max-width: 860px)").matches) return; + if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || + document.querySelector(".site-dialog[open]") || + mobileMenu?.classList.contains("is-open") || + event.target.closest("input, textarea, select, [contenteditable], [role='textbox']")) return; + event.preventDefault(); + if (event.repeat) return; + grid.classList.add("is-closed-after-click"); + if (event.key === "ArrowUp") moveFeature(-1); + if (event.key === "ArrowDown") moveFeature(1); + if (event.key === "ArrowLeft") moveCategory(-1); + if (event.key === "ArrowRight") moveCategory(1); + scheduleAutoplay(); + }); + + // 기술 역량: 본문 스크롤 우선, 끝에서 잠깐 멈춘 뒤 새 휠 입력으로 슬라이드 전환. + if (capabilitiesWorkbench) { + let contentGestureActive = false; + let lastContentWheelAt = 0; + capabilitiesWorkbench.addEventListener("wheel", (event) => { + if (window.matchMedia("(max-width: 860px)").matches) return; + if (event.ctrlKey || Math.abs(event.deltaX) > Math.abs(event.deltaY)) return; + const delta = event.deltaY * (event.deltaMode === 1 ? 16 : event.deltaMode === 2 ? window.innerHeight : 1); + if (!delta) return; + const now = performance.now(); + // Let nested content scroll until it reaches the boundary in this direction. + for (let panel = event.target; panel && panel !== capabilitiesWorkbench; panel = panel.parentElement) { + const overflowY = window.getComputedStyle(panel).overflowY; + if (!["auto", "scroll"].includes(overflowY) || panel.scrollHeight <= panel.clientHeight + 2) continue; + const remaining = panel.scrollHeight - panel.clientHeight - panel.scrollTop; + if (delta > 0 ? remaining > 2 : panel.scrollTop > 2) { + contentGestureActive = true; + lastContentWheelAt = now; + return; + } + } + event.preventDefault(); + // Reaching the edge ends this gesture; advancing needs a fresh gesture after a pause. + if (contentGestureActive && now - lastContentWheelAt < 300) { + lastContentWheelAt = now; + return; + } + contentGestureActive = false; + if (wheelLocked || Math.abs(delta) < 8) return; + wheelLocked = true; + moveFeature(delta > 0 ? 1 : -1); + scheduleAutoplay(); + window.setTimeout(() => { + wheelLocked = false; + }, 520); + }, { passive: false }); + } + + // 기술 역량: 모바일 이전/다음과 공통 재생/멈춤 버튼. + prevButtons.forEach((button) => { + button.addEventListener("click", () => { + moveFeature(-1); + scheduleAutoplay(); + }); + }); + + nextButtons.forEach((button) => { + button.addEventListener("click", () => { + moveFeature(1); + scheduleAutoplay(); + }); + }); + + autoplayButtons.forEach((button) => { + button.addEventListener("click", () => { + autoplayPaused = !autoplayPaused; + scheduleAutoplay(); + }); + }); + + renderProjects(currentFilter); +})(); diff --git a/scripts/generate-capability-thumbnails.mjs b/scripts/generate-capability-thumbnails.mjs new file mode 100644 index 0000000..8530e4c --- /dev/null +++ b/scripts/generate-capability-thumbnails.mjs @@ -0,0 +1,21 @@ +// macOS에서 실행: node scripts/generate-capability-thumbnails.mjs +// 목록용 이미지 축소본만 생성하며 원본과 프로젝트 데이터는 변경하지 않음. +import fs from "node:fs"; +import path from "node:path"; +import vm from "node:vm"; +import { execFileSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const context = { window: {} }; +vm.runInNewContext(fs.readFileSync(path.join(root, "js/capabilities-data.js"), "utf8"), context); +const images = new Set(context.window.CAPABILITY_PROJECTS.flatMap((item) => + [item.image, item.objectImage, item.objectImageSecondary].filter(Boolean))); +let bytes = 0; +for (const source of images) { + const target = path.join(root, source.replace("assets/images/", "assets/thumbnails/")); + fs.mkdirSync(path.dirname(target), { recursive: true }); + execFileSync("sips", ["-Z", "320", path.join(root, source), "--out", target], { stdio: "pipe" }); + bytes += fs.statSync(target).size; +} +console.log(`Generated ${images.size} thumbnails (${Math.round(bytes / 1024)} KB total).`); diff --git a/scripts/generate-capability-webp.mjs b/scripts/generate-capability-webp.mjs new file mode 100644 index 0000000..692467c --- /dev/null +++ b/scripts/generate-capability-webp.mjs @@ -0,0 +1,71 @@ +// 기술 역량 원본 이미지를 웹 전송용 WebP로 변환합니다. +// 실행: node scripts/generate-capability-webp.mjs [--force] +import fs from "node:fs"; +import path from "node:path"; +import vm from "node:vm"; +import { execFileSync } from "node:child_process"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const force = process.argv.includes("--force"); +const context = { window: {} }; +vm.runInNewContext(fs.readFileSync(path.join(root, "js", "capabilities-data.js"), "utf8"), context); + +const sources = new Map(); +for (const item of context.window.CAPABILITY_PROJECTS) { + if (item.image) sources.set(item.image, "background"); + if (item.objectImage) sources.set(item.objectImage, "object"); + if (item.objectImageSecondary) sources.set(item.objectImageSecondary, "object"); +} + +function dimensions(source) { + const output = execFileSync("sips", ["-g", "pixelWidth", "-g", "pixelHeight", source], { + encoding: "utf8", + }); + return { + width: Number(output.match(/pixelWidth: (\d+)/)?.[1]), + height: Number(output.match(/pixelHeight: (\d+)/)?.[1]), + }; +} + +function optimizedPath(source) { + return source + .replace("assets/images/", "assets/images-webp/") + .replace(/\.(?:png|jpe?g)$/i, ".webp"); +} + +let sourceBytes = 0; +let outputBytes = 0; +let generated = 0; + +for (const [relativeSource, type] of sources) { + const source = path.join(root, relativeSource); + const target = path.join(root, optimizedPath(relativeSource)); + const sourceStat = fs.statSync(source); + sourceBytes += sourceStat.size; + fs.mkdirSync(path.dirname(target), { recursive: true }); + + if (!force && fs.existsSync(target) && fs.statSync(target).mtimeMs >= sourceStat.mtimeMs) { + outputBytes += fs.statSync(target).size; + continue; + } + + const { width, height } = dimensions(source); + const maxWidth = type === "background" ? 2560 : 2400; + const maxHeight = type === "background" ? 1800 : 2400; + const scale = Math.min(1, maxWidth / width, maxHeight / height); + const args = ["-quiet", "-mt", "-m", "6", "-q", type === "background" ? "80" : "86"]; + if (type === "background") args.push("-sharp_yuv"); + else args.push("-alpha_q", "100", "-exact"); + if (scale < 1) args.push("-resize", String(Math.round(width * scale)), String(Math.round(height * scale))); + args.push(source, "-o", target); + execFileSync("cwebp", args, { stdio: "inherit" }); + outputBytes += fs.statSync(target).size; + generated += 1; +} + +const savedPercent = Math.round((1 - outputBytes / sourceBytes) * 100); +console.log( + `${generated ? `Generated ${generated}` : "Checked"} WebP assets: ` + + `${(sourceBytes / 1048576).toFixed(1)}MB -> ${(outputBytes / 1048576).toFixed(1)}MB (${savedPercent}% reduction)`, +); diff --git a/scripts/sync-capabilities-seo.mjs b/scripts/sync-capabilities-seo.mjs new file mode 100644 index 0000000..0002fc5 --- /dev/null +++ b/scripts/sync-capabilities-seo.mjs @@ -0,0 +1,102 @@ +// 수동 실행: new_home v1 폴더에서 node scripts/sync-capabilities-seo.mjs +// capabilities-data.js의 내용을 capabilities.html의 정적 SEO 영역에 반영함. +// 브라우저에서는 실행되지 않으며, 프로젝트 내용을 수정한 뒤 배포 전에 실행. +import fs from "node:fs"; +import path from "node:path"; +import vm from "node:vm"; +import { fileURLToPath } from "node:url"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const root = path.resolve(__dirname, ".."); +const dataPath = path.join(root, "js", "capabilities-data.js"); +const htmlPath = path.join(root, "capabilities.html"); + +const context = { window: {} }; +vm.createContext(context); +vm.runInContext(fs.readFileSync(dataPath, "utf8"), context); + +const projects = context.window.CAPABILITY_PROJECTS || []; +const projectIds = new Set(); +for (const item of projects) { + if (!item.id || projectIds.has(item.id)) { + throw new Error(`Missing or duplicate project ID: ${item.id}`); + } + projectIds.add(item.id); + for (const field of ["image", "objectImage", "objectImageSecondary"]) { + if (item[field] && !fs.existsSync(path.resolve(root, item[field]))) { + throw new Error(`Missing capabilities image (${item.id}): ${item[field]}`); + } + } +} +const groups = [ + ["automotive", "Automotive 전장 기술 역량"], + ["robotics", "Robotics 로봇 기술 역량"], + ["solution", "Solution 솔루션 기술 역량"], + ["si", "SI 웹·앱 개발 사례"], + ["certifications", "Certifications 특허 기술 역량"], +]; + +function escapeHtml(value = "") { + return String(value) + .replace(/&/g, "&") + .replace(//g, ">") + .replace(/"/g, """) + .replace(/'/g, "'"); +} + +function normalizeText(value = "") { + return String(value).replace(/\s+/g, " ").trim(); +} + +function renderProject(item) { + const subtitle = item.subtitle + ? `\n

${escapeHtml(item.subtitle)}

` + : ""; + const description = item.layout === "table" + ? "자동차 전장 개발 및 컨설팅 이력을 사업명과 사업기간 기준으로 정리한 기타 수행 프로젝트 목록입니다." + : normalizeText(item.description); + const tableRows = item.tableRows + ? `\n ` + : ""; + + return `
+

${escapeHtml(item.title)}

${subtitle} +

${escapeHtml(description)}

${tableRows} +
`; +} + +const sections = groups.map(([type, title]) => { + const items = projects.filter((item) => item.type === type); + return `
+

${escapeHtml(title)}

+${items.map(renderProject).join("\n")} +
`; +}).join("\n"); + +const block = ` +
+

모비핀테크놀러지 기술 역량

+

+ 모비핀테크놀러지는 자동차 전장, 로봇, 솔루션, SI 영역에서 실제 운영 환경에 적용되는 소프트웨어를 개발합니다. +

+${sections} +
+ `; + +const html = fs.readFileSync(htmlPath, "utf8"); +const markerPattern = /[\s\S]*?/; +if (!markerPattern.test(html)) { + throw new Error("SEO marker block was not found in capabilities.html"); +} +const next = html.replace( + markerPattern, + block, +); + +if (next !== html) { + fs.writeFileSync(htmlPath, next); + console.log(`Updated capabilities.html SEO content (${projects.length} projects).`); +} else { + console.log(`SEO content is already up to date (${projects.length} projects).`); +}