HTML6 Games설치없는 무료 웹 게임 / devlog

설치 없이, 지금 바로 플레이

브라우저에서 즐기는 무료 미니게임 모음. 로그인하면 기록이 계정에 저장되어 어느 기기에서든 이어서 볼 수 있어요.

게임 목록
게임 목록
모든 개발 이야기

3D 모델의 텍스처가 하얗게 나왔다

2026년 10월 30일 · 기술

타워크레인은 상자 도형을 코드로 만들어 그림 파일이 없었다. 두 번째 3D 게임인 러시 3D 는 처음으로 모델 파일을 썼다. Kenney 가 CC0 로 공개한 Platformer Kit 에서 캐릭터와 소품 모델 15개를 골랐다. 3D 모델 파일의 표준 형식인 glTF 의 바이너리판(glb)이다.

모델 15개를 따로 받으면 요청이 15번이다. 그래서 쓰는 모델을 glb 파일 하나(pack.glb, 208KB)로 묶었다. 재질과 텍스처도 하나만 쓰도록 맞췄다. 게임은 이 파일을 등록에 적어 두면, 사이트가 그림 파일처럼 공통 로딩 화면에서 받는다. three.js 가 도착하면 GLTFLoader 로 읽은 뒤 게임을 시작한다. 게임 코드는 이름으로 모델의 복제본을 꺼내 쓴다. 뼈대가 있는 캐릭터는 그냥 복제하면 뼈대가 따라오지 않아서, three.js 의 부품(SkeletonUtils)으로 복제한다.

assets: { base: '/games/rush3d/', models: { pack: 'models/pack.glb' } },
mount(stage, api) {
  const hero = api.model('pack', 'character-oopi');   // a clone of that node (skeleton included)
  const anim = k.anim(hero, api.clips('pack', 'character-oopi')).play('idle');
}

텍스처가 하얗게 나왔다

처음 불러왔을 때 모델의 모양은 맞는데 텍스처가 붙지 않고 하얗게 나왔다. 콘솔에는 보안 설정(CSP)의 connect-src 를 어겼다는 오류가 있었다.

glb 파일 안에는 텍스처 그림이 함께 들어 있다. GLTFLoader 는 이 그림을 꺼내 브라우저 메모리 안의 임시 주소로 만든다. blob: 로 시작하는 주소다. 그리고 그 주소를 다시 fetch 로 읽어 텍스처로 올린다. 이 사이트의 보안 설정은 자바스크립트가 연결할 수 있는 주소(connect-src)와 그림을 읽을 수 있는 주소(img-src)를 정해 두고 있었는데, 여기에 blob: 이 없었다. 그래서 텍스처를 읽는 요청이 막히고, 모델은 그림 없이 흰색으로 그려졌다.

두 곳에 blob: 을 더했다. 그런데 헤더를 고쳐도 로컬 화면은 그대로였다. 로컬에서 쓰는 Firebase 에뮬레이터는 시작할 때 설정 파일을 읽어서, 헤더를 바꾼 뒤에는 에뮬레이터를 다시 띄워야 반영된다. 이 점을 모르면 고친 설정이 안 먹는 것처럼 보인다.

다시 묶은 모델이 캐시에 남았다

모델을 고쳐 pack.glb 를 다시 묶어도 브라우저가 옛 파일을 계속 쓸 수 있다는 것을 알았다. 그때 캐시 헤더 규칙은 JS, CSS, HTML 에만 있었고 glb 는 빠져 있었다. 규칙에 걸리지 않은 파일에는 Firebase 의 기본 캐시가 붙는데, 그 값이 1시간이라 다시 묶은 모델이 최대 1시간 늦게 보인다. 그래서 glb 도 다른 코드 파일과 같은 캐시 규칙에 넣었다. 캐시 헤더가 요청 주소에 따라 걸리는 방식은 다른 글에 따로 적었다.

참고한 문서

이 글과 관련된 게임

러시 3D하늘에 떠 있는 섬들을 잇는 세 줄 블록 길을 달려요. 줄을 바꾸고, 뛰고, 숙여서 장애물과 끊긴 길을 피하세요. 얼마나 멀리 갈 수 있을까요? 해 보기

다른 글

홈 화면에 추가하기

  1. 화면 아래(아이패드는 위)의 공유 버튼을 누르세요. 네모에서 화살표가 위로 나온 모양이에요.
  2. 목록을 내려 "홈 화면에 추가"를 누르세요.
  3. 오른쪽 위 "추가"를 누르면 홈 화면에 HTML6 Games 아이콘이 생겨요.

Safari 에서만 추가할 수 있어요. 홈 화면에서 열면 주소창 없이 앱처럼 보이고, 인터넷이 끊겨도 열립니다.