| 일 | 월 | 화 | 수 | 목 | 금 | 토 |
|---|---|---|---|---|---|---|
| 1 | 2 | 3 | ||||
| 4 | 5 | 6 | 7 | 8 | 9 | 10 |
| 11 | 12 | 13 | 14 | 15 | 16 | 17 |
| 18 | 19 | 20 | 21 | 22 | 23 | 24 |
| 25 | 26 | 27 | 28 | 29 | 30 | 31 |
- #GoogleAIStudio
- GEMINI
- 포켓 월드
- AI스토리북
- gemini 4.0
- 고고천문학
- Anthropic
- GitHub Pages 배포
- react
- AI 코딩
- Google AI Studio
- 차코캐니언
- GPT-6
- threejs
- ChatGPT
- webgl
- openai
- 회계 장부 인터랙티브 대시보드
- 자연어 질의
- ai모델비교
- desk racer
- 아르곤 테니스
- 재무 데이터 시각화
- TypeScript
- cozy plow
- Gemini/Managed Agent
- ManagedAgent
- argon
- ai studio
- githubPages
- Today
- Total
AI 로 실현하는 디지털 생활의 즐거움. DiJoy AI
AI Studio로 만든 포켓 월드 테라리움: Three.js 구현과 웹 배포 본문

"책상 위 유리 구체 속에 나만의 작은 행성이 살아서 숨 쉬고 있다면?"
Google AI Studio를 활용하여 기획부터 Three.js 3D 로우폴리 렌더링, 주민/양 떼 시뮬레이션, 한글/영문 다국어 지원, 그리고 GitHub Pages 배포까지 완성한 풀스토리 개발기를 공유합니다.
📌 목차
- 프로젝트 소개 & 완성 모습
- Google AI Studio와 함께한 개발 경험 (바이브 코딩)
- 기술 스택 및 시스템 아키텍처
- 핵심 기술 구현 & 심층 코드 분석
- ① 다면체 구체 행성(Icosphere) 지형 및 노이즈 조각
- ② 테라리움 유리 구체(Orb) 셰이딩 & 호두나무 스탠드
- ③ 살아 숨 쉬는 로우폴리 미니어처 오브젝트 23종
- ④ 구체 표면 위 자율 보행 에이전트 (주민 & 양 떼)
- ⑤ 30초 시네마틱 카메라 투어 & 실시간 일주(Day-Night) 사이클
- ⑥ 기본 한국어(KO) 및 영문(EN) 바이링구얼 시스템
- GitHub 및 GitHub Pages 배포하기
- 마치며 & 배포 링크
1. 프로젝트 소개 & 완성 모습
포켓 월드 테라리움 (Pocket World Terrarium)은 따뜻한 호두나무 받침대 위에 놓인 맑은 유리 구체 안에, 떠 있는 다면체 행성을 마우스로 돌려가며 마을을 가꾸고 지형을 조각하는 아늑한(Cozy) 3D 인터랙티브 미니어처 시뮬레이션 웹 애플리케이션입니다.
- 23종의 오브젝트 & 조각 도구: 파스텔톤 전원주택, 천천히 회전하는 풍차, 바다를 비추는 해안 등대, 밤마다 주민들이 모이는 모닥불, 하늘을 띄우는 열기구와 무지개, 물결치는 에메랄드빛 바다와 돛단배, 그리고 대지를 솟구치게 하거나 깎아내는 지형 스컬프팅.
- 살아있는 생태계: 초원을 뛰어다니며 꼬리를 흔들고 풀을 뜯는 아기 양들, 우물과 집 사이를 산책하는 귀여운 주민들, 바다 위를 유유자적 노니는 백조와 오리 무리.
- 동적 낮/황혼/밤 사이클: 시간에 따라 방 창문으로 들어오는 햇살이 달라지고, 황혼이 되면 가로등과 집 창문, 등대에 주황빛 불이 켜지며, 밤이 되면 반딧불이와 별똥별이 테라리움 안을 수놓습니다.
- 언어 지원: 기본 언어로 한국어를 지원하며, 상단 버튼 하나로 영어(English)로 실시간 전환 가능합니다.
2. Google AI Studio와 함께한 개발 경험
이번 프로젝트는 Google AI Studio를 적극적으로 활용하여 제작되었습니다. 보통 3D 웹 프로젝트는 수많은 삼각함수, 구면 좌표계 변환, Three.js 셰이더와 버퍼 지오메트리 등 진입장벽이 높지만, AI Studio를 파트너 삼아 다음과 같은 단계로 빠르고 견고하게 완성할 수 있었습니다.
💡 AI Studio 활용 팁 & 워크플로우
- 정확한 비주얼 & 감성 컨셉 프롬프팅:
단순히 "3D 행성 만들어줘"가 아닌, *"책상 위 은은한 램프 빛이 비치는 방, 고급스러운 호두나무 베이스와 황동 링 받침대 위에 올려진 유리 테라리움 구체, 그 안에 떠 있는 파스텔톤 다면체(low-poly faceted) 소행성"*과 같이 재질감과 광원 설정을 구체적으로 정의했습니다. - 수학적 난제 해결:
구체 표면에 오브젝트를 법선(Normal) 방향으로 올바르게 세우는 쿼터니언 회전 수식, 지형을 마우스 클릭으로 융기(Raise)시킬 때 구면 거리를 계산하는 하버사인(Haversine) 유사 알고리즘, 구체 표면 위에서 주민들이 울타리를 뚫지 못하게 막는 충돌 감지 로직을 AI Studio와 함께 수월하게 해결했습니다. - 컴포넌트와 씬의 명확한 관심사 분리:
Three.js 렌더링 캔버스 엔진(PocketWorldScene.ts), 절차적 3D 메쉬 생성(MiniatureObjects.ts, PlanetTerrain.ts), 그리고 React 상태와 다국어 UI(App.tsx, translations.ts)를 깔끔하게 분리하여 확장성과 유지보수성을 극대화했습니다.
3. 기술 스택 및 시스템 아키텍처
- Core Engine: Three.js (r186)
- Frontend Framework: React 19 + TypeScript (Strict Mode)
- Styling: Tailwind CSS v4 + Lucide React Icons
- Build Tool: Vite 8 + ESBuild
- CI/CD: GitHub Actions + GitHub Pages
/
├── .github/workflows/deploy.yml # GitHub Pages 자동 배포 파이프라인
├── src/
│ ├── i18n/
│ │ └── translations.ts # 한글/영문 사전 및 도구 메타데이터
│ ├── three/
│ │ ├── MiniatureObjects.ts # 23종 미니어처 메쉬 생성 및 애니메이션
│ │ ├── PlanetTerrain.ts # 구체 다면체 지형 및 바다 버퍼 지오메트리
│ │ ├── PocketWorldScene.ts # Three.js 씬, 물리/이동 시뮬레이션, 카메라 투어
│ │ └── RoomEnvironment.ts # 아늑한 실내 조명, 유리 구체, 호두나무 베이스
│ ├── types/
│ │ └── world.ts # 전역 월드 상태 및 도구 타입 정의
│ ├── App.tsx # React 반응형 인터페이스, HUD, 모달, i18n
│ ├── main.tsx
│ └── index.css
├── vite.config.ts # base: './' 설정으로 서브경로 완벽 호환
└── package.json
4. 핵심 기술 구현 & 심층 코드 분석
① 다면체 구체 행성(Icosphere) 지형 및 노이즈 조각
로우폴리 감성의 핵심은 부드러운 구가 아닌, 적절하게 면이 분할된(Faceted) 구체 메쉬를 사용하는 것입니다. IcosahedronGeometry를 기반으로 정점들을 방사형 벡터로 밀어내고, 높이(elevation) 데이터를 각 정점에 동적으로 부여합니다.
// PlanetTerrain.ts 일부 발췌: 정점 높이 및 바다/육지 판정
export function createPlanetTerrain(radius = 1.0) {
const geom = new THREE.IcosahedronGeometry(radius, 4);
const posAttr = geom.attributes.position;
const vertexCount = posAttr.count;
const elevations = new Float32Array(vertexCount);
const baseVectors: THREE.Vector3[] = [];
// 기본 구체 형상 저장
for (let i = 0; i < vertexCount; i++) {
const v = new THREE.Vector3().fromBufferAttribute(posAttr, i).normalize();
baseVectors.push(v);
elevations[i] = 0; // 0 = 평지, >0 = 산/언덕, <0 = 호수/바다
}
// 지형 올리기/낮추기 (Sculpting) 실시간 연산
function deformTerrain(centerDir: THREE.Vector3, radiusAngle: number, deltaHeight: number) {
for (let i = 0; i < vertexCount; i++) {
const dist = centerDir.distanceTo(baseVectors[i]);
if (dist < radiusAngle) {
// 코사인 스무스 감쇄 곡선 적용
const factor = Math.cos((dist / radiusAngle) * (Math.PI * 0.5));
elevations[i] = Math.max(-0.25, Math.min(0.4, elevations[i] + deltaHeight * factor));
// 정점 위치 재계산
const curR = radius * (1.0 + elevations[i]);
posAttr.setXYZ(i, baseVectors[i].x * curR, baseVectors[i].y * curR, baseVectors[i].z * curR);
}
}
posAttr.needsUpdate = true;
geom.computeVertexNormals(); // 플랫 셰이딩 느낌의 재계산
}
return { geom, deformTerrain };
}
② 테라리움 유리 구체(Orb) 셰이딩 & 호두나무 스탠드
미니어처 행성이 현실의 방 안 책상 위에 떠 있는 느낌을 주기 위해, 외곽에 반투명한 유리 구체(MeshPhysicalMaterial)와 하단에 정교한 호두나무 원목 스탠드를 배치했습니다.
// RoomEnvironment.ts 일부: 투명 굴절 유리와 프레넬 반사
const glassMaterial = new THREE.MeshPhysicalMaterial({
color: 0xffffff,
metalness: 0.05,
roughness: 0.08,
transmission: 0.92, // 유리 투과율
ior: 1.48, // 유리 굴절률(Index of Refraction)
thickness: 0.12,
transparent: true,
opacity: 0.65,
specularIntensity: 1.0,
specularColor: new THREE.Color(0xfff7e6),
depthWrite: false,
});
const glassOrb = new THREE.Mesh(new THREE.SphereGeometry(1.42, 48, 48), glassMaterial);
scene.add(glassOrb);
③ 23가지 미니어처 오브젝트의 절차적 모델링
외부 무거운 3D glTF 파일을 로드하는 대신, Three.js의 기본 지오메트리(박스, 원뿔, 실린더, 토러스)를 조합하여 가볍고 사랑스러운 로우폴리 오브젝트들을 코드로 생성했습니다.
예를 들어, 풍차(Windmill)는 하얀 원뿔형 본체에 나무 지붕, 그리고 4개의 캔버스 돛이 십자 형태로 회전하도록 설계되었습니다:
// MiniatureObjects.ts: 풍차 날개 회전 애니메이션 구조
export function createWhiteWindmillMesh() {
const group = new THREE.Group();
// 본체 & 지붕
const bodyGeo = new THREE.CylinderGeometry(0.016, 0.024, 0.065, 8);
const bodyMat = new THREE.MeshStandardMaterial({ color: 0xf5f3ee, roughness: 0.8 });
const body = new THREE.Mesh(bodyGeo, bodyMat);
group.add(body);
// 회전하는 4익 날개 그룹
const sailsPivot = new THREE.Group();
sailsPivot.position.set(0, 0.025, 0.018);
for (let i = 0; i < 4; i++) {
const blade = createSailBladeMesh();
blade.rotation.z = (Math.PI / 2) * i;
sailsPivot.add(blade);
}
group.add(sailsPivot);
return {
mesh: group,
update: (dt: number) => {
sailsPivot.rotation.z += dt * 1.5; // 지속적인 자연스러운 회전
}
};
}
④ 구체 표면 위 자율 보행 에이전트 (주민 & 양 떼)
평면 맵에서의 AI 이동은 쉽지만, 곡면 구체 위에서의 이동은 색다른 도전 과제입니다.
- 현재 지점 $P$에서 목표 지점 $Target$으로 호(Arc)를 그리며 이동.
- 행성 중심에서 바깥으로 나가는 법선(Normal)을 위쪽 축($+Y$)으로 정렬하는 쿼터니언 변환.
- 울타리(Fence) 및 주택(House), 바다(Water)와의 충돌 분기 처리.
// 구체 위 표면 법선과 이동 방향에 맞춰 오브젝트를 직립 & 회전시키는 핵심 수식
const surface = terrain.getSurfacePointAndNormal(entity.currentDir);
entity.mesh.position.copy(surface.point);
// 1. 구체 표면에 발을 수직으로 딛도록 상향 벡터 정렬
const alignQuat = new THREE.Quaternion().setFromUnitVectors(
new THREE.Vector3(0, 1, 0),
surface.normal
);
// 2. 이동하고자 하는 접선(Tangent) 방향으로 바라보기
const tangent = entity.targetDir.clone().sub(entity.currentDir).projectOnPlane(surface.normal).normalize();
const localAngle = Math.atan2(tangent.x, tangent.z);
const yawQuat = new THREE.Quaternion().setFromAxisAngle(new THREE.Vector3(0, 1, 0), localAngle);
// 3. 최종 회전 적용
entity.mesh.quaternion.copy(alignQuat).multiply(yawQuat);
⑤ 30초 시네마틱 카메라 투어 & 실시간 일주(Day-Night) 사이클
사용자가 30초 투어(30s Tour) 버튼을 누르면 카메라는 궤도 조망(Orbit) ➔ 아늑한 마을 골목(Village) ➔ 에메랄드빛 해안가(Coast) ➔ 전체 테라리움 감상(Overview)으로 이어지는 스플라인 경로를 부드럽게 글라이딩합니다.
또한, 상단에는 남은 시간 카운트다운과 [투어 종료] 버튼이 포함된 시네마틱 오버레이 HUD가 표시됩니다.
⑥ 기본 한국어(KO) 및 영문(EN) 바이링구얼 시스템
국내 사용자에게 친숙한 기본 한국어 인터페이스를 탑재했습니다. src/i18n/translations.ts를 통해 모든 도구 이름과 상세 설명, 카메라 시점, 날씨 명칭까지 번역되어 있으며, 화면 좌상단의 언어 토글 버튼으로 실시간 전환됩니다.
// translations.ts 예시
export const UI_STRINGS = {
ko: {
defaultPlanetName: '작은 초원',
stats: { pop: '주민', happy: '행복도', day: '일차' },
actions: { grow: '확장하기', tour30s: '30초 투어', exitTour: '투어 종료' },
// ...
},
en: {
defaultPlanetName: 'Little Meadow',
stats: { pop: 'Pop', happy: 'Happy', day: 'Day' },
actions: { grow: 'Grow', tour30s: '30s Tour', exitTour: 'Exit Tour' },
// ...
}
};
5. GitHub 및 GitHub Pages 배포하기
이 멋진 프로젝트를 다른 사람들과 공유하기 위해 GitHub 원격 저장소에 소스를 업로드하고, 누구나 웹 브라우저에서 바로 실행해볼 수 있도록 GitHub Pages에 배포했습니다.
1) Vite 베이스 경로 설정 (vite.config.ts)
GitHub Pages의 서브 디렉터리(https://<아이디>.github.io/<리포지토리>/)에서도 정적 애셋(CSS, JS)이 404 에러 없이 불러와지도록 base: './' 상대 경로를 설정했습니다:
export default defineConfig(() => {
return {
base: './', // 상대 경로로 어디서든 완벽 동작
plugins: [react(), tailwindcss()],
// ...
};
});
2) GitHub Actions 자동 배포 파이프라인 (.github/workflows/deploy.yml)
main 브랜치에 코드를 푸시할 때마다 자동으로 빌드되고 배포되도록 GitHub Actions 워크플로우를 구성했습니다.
6. 마치며 & 배포 링크
웹 브라우저 안에서 작은 세상을 빚어내고 주민들의 소소한 일상을 지켜보는 것은 개발하는 내내 큰 힐링이었습니다. 특히 Google AI Studio 덕분에 Three.js의 까다로운 3D 수학과 셰이더, 애니메이션 루프를 빠르게 구축할 수 있었습니다.
직접 나만의 테라리움 행성을 만들고 가꿔보세요!
- 🌐 웹 라이브 데모 (GitHub Pages):
👉 https://djai32521.github.io/Pocket_World_Terrarium/ - 📂 GitHub 소스코드 리포지토리:
👉 https://github.com/djai32521/Pocket_World_Terrarium
포스팅이 도움이 되셨다면 공감과 댓글 부탁드립니다! 궁금한 점은 언제든 댓글로 남겨주세요.