Skip to content

2026년 웹 게임 기술 스택

웹 게임을 돌아가게 하는 기술은 세 가지입니다. WebGL, WebGPU, WebAssembly죠. 각각 해결하는 문제가 다르고 따라오는 트레이드오프도 다릅니다. 이 가이드는 가장 화제가 되는 기술이 아니라 여러분이 실제로 만드는 게 무엇인지를 기준으로 고르도록 돕습니다.

빠른 결론

WebGL 2.0은 어디서나 돌아가고 대부분의 게임을 무리 없이 처리합니다. 넓은 호환성이 필요할 때, 특히 모바일에서 쓰세요. WebGPU는 컴퓨트 셰이더와 더 나은 성능을 주지만, 오래된 브라우저와 기기를 쓰는 사용자를 잃게 됩니다. WebAssembly는 CPU 코드를 더 빠르게 만들어 주니 물리나 경로 탐색에 유용합니다. 다만 병목이 GPU라면 도움이 안 됩니다.

2026년 대부분의 게임은 WebGL로 출시하면서, 지원되는 브라우저를 위해 선택적으로 WebGPU를 얹습니다. Wasm은 게임 전체가 아니라 자주 실행되는 핫 코드 경로에만 골라서 씁니다.

WebGL 2.0: 지루하지만 잘 돌아가는 선택

WebGL 2.0은 2017년부터 안정적이었습니다. 모든 최신 브라우저가 지원하죠. 여러분의 게임은 5년 이상 거슬러 올라가는 Chrome, Firefox, Safari, Edge에서 돌아갑니다. iOS Safari 15 이상, Chrome for Android, Samsung Internet에서도 동작합니다. 심지어 Xbox Edge나 PlayStation 브라우저 같은 콘솔 브라우저에서도 돌아갑니다.

기본적인 WebGL 2 설정은 이렇게 생겼습니다.

javascript
const canvas = document.getElementById('game');
const gl = canvas.getContext('webgl2');

if (!gl) {
  // WebGL 1로 폴백하거나 오류 표시
  const gl1 = canvas.getContext('webgl');
  if (!gl1) {
    showError('Your browser does not support WebGL.');
    return;
  }
}

// 이제 GL 컨텍스트가 생겼습니다
gl.clearColor(0.1, 0.1, 0.1, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);

얻는 것

WebGL 2는 인스턴스 렌더링을 제공해서 드로우 콜 하나로 수천 개의 오브젝트를 그릴 수 있습니다. GPU 측 파티클 시스템과 시뮬레이션을 위한 transform feedback도 있죠. 디퍼드 렌더링과 G-buffer를 위한 다중 렌더 타겟, 볼류메트릭 효과를 위한 3D 텍스처, 정밀한 데이터 저장을 위한 정수 텍스처도 얻습니다.

javascript
gl.drawArraysInstanced(gl.TRIANGLES, 0, vertexCount, instanceCount);

얻지 못하는 것

범용 GPU 연산을 위한 컴퓨트 셰이더는 돌릴 수 없습니다. 바인드리스 텍스처가 없어서 텍스처 유닛 개수에 제약을 받습니다. 영속 매핑이나 명시적 메모리 제어도 없습니다. 메시 셰이더나 현대적인 지오메트리 파이프라인도 없죠.

대부분의 2D 게임과 많은 3D 게임에서 이런 제약은 문제가 되지 않습니다. WebGL 2는 역사상 가장 성공한 웹 게임들을 여럿 출시시켰습니다.

WebGPU: 더 많은 게 필요할 때

WebGPU는 현대 GPU가 실제로 동작하는 방식을 중심으로 설계됐습니다. Chrome이 2023년 5월에 출시했고, 2025년 말에는 모든 주요 브라우저가 지원하게 됐습니다. Chrome 113 이상, Firefox 145 이상, Safari 26 이상, Edge 113 이상에서 모두 동작합니다. Chrome Android는 최신 기기에서 지원하고, iOS Safari 26 이상도 지원합니다.

문제는 오래된 기기와 브라우저에는 이게 없다는 점입니다. 그래서 폴백 전략이 필요합니다.

얻는 것

컴퓨트 셰이더로 물리, 파티클, AI, 이미지 처리에 쓰는 범용 GPU 연산을 돌릴 수 있습니다.

javascript
// 데이터를 병렬로 처리하는 컴퓨트 셰이더
const computeShaderCode = `
@group(0) @binding(0) var<storage, read_write> data: array<f32>;

@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) id: vec3<u32>) {
  data[id.x] = data[id.x] * 2.0;
}
`;

명시적 리소스 관리도 얻는데, 이건 성능이 예상 밖으로 튀는 일이 줄어든다는 뜻입니다. 반복 사용할 드로우 콜을 미리 기록하는 render bundle도 있고, C 스타일 편법이 아니라 GPU를 위해 설계된 현대적 셰이더 언어인 WGSL도 있습니다.

실전 WebGPU 설정

WebGL 폴백과 함께 WebGPU를 초기화하는 방법은 이렇습니다.

javascript
async function initGraphics(canvas) {
  // 먼저 WebGPU 시도
  if (navigator.gpu) {
    const adapter = await navigator.gpu.requestAdapter();
    if (adapter) {
      const device = await adapter.requestDevice();
      const context = canvas.getContext('webgpu');
      
      context.configure({
        device,
        format: navigator.gpu.getPreferredCanvasFormat(),
      });
      
      return { type: 'webgpu', device, context };
    }
  }
  
  // WebGL 2로 폴백
  const gl = canvas.getContext('webgl2');
  if (gl) {
    return { type: 'webgl2', gl };
  }
  
  // 최후의 수단: WebGL 1
  const gl1 = canvas.getContext('webgl');
  if (gl1) {
    return { type: 'webgl', gl: gl1 };
  }
  
  throw new Error('No graphics API available');
}

실제로 도움이 되는 경우

WebGPU는 이럴 때 빛을 발합니다. CPU 왕복 없이 수백만 개의 파티클을 갱신하는 컴퓨트 셰이더가 필요할 때, GPU 가속 충돌 감지와 천 시뮬레이션이 필요할 때, 지형이나 텍스처나 메시를 절차적으로 생성할 때, SSAO나 블룸이나 피사계 심도 같은 복잡한 후처리 효과를 쓸 때, 또는 NPC 행동이나 이미지 효과를 위해 학습된 모델을 돌리고 싶을 때죠.

퍼즐 게임이나 비주얼 노벨을 만든다면 WebGPU는 도움이 안 됩니다. 파티클이 많은 액션 게임이나 복잡한 3D 세계를 만든다면 호환성 트레이드오프를 감수할 가치가 있을 수 있습니다.

WebAssembly: 빠른 CPU 코드

WebAssembly는 컴파일된 코드를 거의 네이티브에 가까운 속도로 실행합니다. 그래픽에 관한 게 아닙니다. CPU 코드를 더 빠르게 만드는 일이죠.

도움이 되는 경우

Wasm은 물리 엔진(Box2D, Bullet, Rapier 모두 Wasm 빌드가 있습니다), 큰 그리드에서의 경로 탐색, 에셋 압축 해제, 옛 게임 콘솔 에뮬레이션, 그리고 기존 C++나 Rust 코드베이스를 웹으로 포팅할 때 잘 맞습니다.

도움이 안 되는 경우

GPU는 드로우 콜이 JavaScript에서 오든 Wasm에서 오든 신경 쓰지 않으니 렌더링이 빨라지지 않습니다. 에셋 가져오기나 네트워크 요청 같은 I/O 바운드 코드도 이득이 없습니다. 그리고 여러분의 JavaScript가 이미 1밀리초 안에 돌고 있다면 Wasm은 도움이 안 됩니다.

실전 Wasm 예제

물리를 위해 Wasm으로 컴파일한 최소한의 Rust 함수는 이렇습니다.

rust
// src/lib.rs
#[no_mangle]
pub extern "C" fn step_physics(dt: f32) {
    // 여기에 물리 코드 작성
}

이렇게 컴파일합니다.

bash
wasm-pack build --target web

JavaScript에서 이렇게 씁니다.

javascript
import init, { step_physics } from './physics_bg.wasm';

await init();

function gameLoop(dt) {
  step_physics(dt); // 거의 네이티브에 가까운 속도로 실행
  render();
  requestAnimationFrame(gameLoop);
}

스레딩은 복잡해집니다

Wasm은 병렬 처리를 위해 스레드를 쓸 수 있지만 SharedArrayBuffer가 필요합니다. 즉 서버에 교차 출처 격리(cross-origin isolation) 헤더가 있어야 한다는 뜻이죠.

Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp

이 헤더들은 여러 가지를 망가뜨립니다. CORP 헤더가 없는 서드파티 iframe이 동작을 멈추고, 일부 분석 스크립트가 깨지며, OAuth 팝업이 실패할 수 있습니다. 피해를 줄이려고 require-corp 대신 credentialless를 쓸 수 있지만 그래도 지저분합니다.

공유 호스팅이나 itch.io에 있어서 이 헤더들을 설정할 수 없다면 Wasm 스레드는 쓸 수 없습니다. 그래도 단일 스레드 Wasm은 잘 돌아갑니다.

실제 게임을 위한 실제 결정

2D 플랫포머를 만든다면 Phaser나 PixiJS 같은 걸 통해 WebGL 2를 쓰세요. WebGPU는 과합니다. 건너뛰세요. Wasm도 건너뛰세요. JavaScript는 2D 물리에 충분히 빠릅니다. 최신 기능보다 넓은 호환성이 더 중요하고, 여러분의 병목은 기술이 아니라 콘텐츠입니다.

3D 오픈 월드를 만든다면 WebGL 2로 시작하되 WebGPU 업그레이드 경로를 염두에 두고 설계하세요. Rapier나 Bullet을 써서 물리를 Wasm으로 돌리는 것도 고려해 보세요. 지금은 최대한 넓게 도달하고 싶지만, 컴퓨트 셰이더는 나중에 식생, 파티클, LOD에 도움이 됩니다. 물리를 Wasm에 두면 CPU 예산을 낮게 유지할 수 있습니다.

C++ 엔진을 포팅한다면 Emscripten을 통해 Wasm을 쓰세요. 그래픽은 기본적으로 WebGL 2가 되고, 엔진이 지원하면 WebGPU가 됩니다. 이미 코드가 있고 번역은 Emscripten이 처리합니다.

퍼즐 게임을 만든다면 Canvas 2D나 Phaser를 통한 WebGL 2를 쓰세요. 나머지는 다 건너뛰세요. 단순한 게임은 단순하게 두는 게 맞습니다.

최대 성능이 반드시 필요하고 오래된 브라우저의 일부 사용자를 잃을 각오가 됐다면 WebGPU에 Wasm을 더해서 가세요. 다만 결정하기 전에 여러분의 사용자에게 실제로 미치는 영향을 먼저 측정하세요.

게임을 실제로 빠르게 만드는 것

웹 게임이 잘 돌아갈지를 결정하는 요인을 중요한 순서대로 정리하면 이렇습니다.

에셋 크기가 체감 성능의 절반쯤을 차지합니다. 1초 만에 로드되는 2MB 게임이 FPS가 더 좋은 50MB 게임보다 빠르게 느껴집니다. 전부 압축하세요. 가능한 건 지연 로드하세요.

드로우 콜은 3D 게임에서 아주 중요해서 성능 예산의 30%쯤 됩니다. 지오메트리를 배칭하세요. 텍스처 아틀라스를 쓰세요. 반복되는 오브젝트는 인스턴싱하세요. 이게 WebGL이냐 WebGPU냐보다 훨씬 더 중요합니다.

JavaScript 성능은 15%쯤입니다. 핫 루프에서 할당을 피하세요. 타입 배열을 쓰세요. 최적화하기 전에 프로파일링부터 하세요.

그래픽 API 선택은요? 솔직히 5%쯤입니다. 대부분의 게임에서는 어떤 API냐보다 그걸 어떻게 쓰느냐가 더 중요합니다.

게임이 느리다면 먼저 앞단에서 너무 많이 로드하고 있는지 확인하세요. 그다음 드로우 콜을 너무 많이 날리고 있는지 확인하세요. 그다음 게임 루프에서 JavaScript가 멍청한 짓을 하고 있는지 확인하세요. 이 모든 걸 다 한 다음에야 다른 그래픽 API가 도움이 될지 물어볼 차례입니다.

내가 실제로 쓸 것

오늘 새 웹 게임을 시작한다면 렌더링에는 Three.js나 Babylon.js를 쓰겠습니다. 둘 다 WebGL과 WebGPU를 추상화해 주니까요. 물리는 3D 물리가 필요하면 Rapier(Wasm으로 컴파일한 Rust)를 쓰고, 더 단순한 게임이면 엔진에 내장된 2D 물리를 그냥 쓰겠습니다. 오디오는 Howler.js나 Web Audio API를 직접 쓰겠습니다. 빌드에는 Vite를 쓰는데 개발할 때 빠르고 프로덕션 빌드도 잘 뽑아 줍니다. 그리고 Netlify, Vercel, GitHub Pages, itch.io에 정적 호스팅하겠습니다.

이 스택은 기기의 98% 이상에서 동작하는 게임을 출시하면서, WebGPU가 기본이 됐을 때를 대비한 준비도 됩니다.

결정하기 전에 테스트하세요

기술 스택을 확정하기 전에 작은 프로토타입을 만들어서 실제로 테스트하세요. Chrome DevTools 스로틀링으로 3G에서 로드 시간을 확인하세요. 느린 연결에서 5초 안에 플레이 가능해야 합니다. 저사양 안드로이드 폰에서 성능을 테스트하세요. 빌려 쓰거나 BrowserStack을 쓰면 됩니다. 거기서 돌아가면 어디서나 돌아갑니다. Safari는 따로 꼭 테스트하세요. 충분히 달라서 예상치 못한 일이 생기거든요. 그리고 게임이 Newgrounds나 Kongregate에 올라간다면 iframe 안에서 테스트하세요.

이런 테스트들이 WebGL이냐 WebGPU냐를 두고 갑론을박하는 것보다 실제 문제를 훨씬 더 많이 잡아냅니다.

더 읽을거리

웹 게임 엔진 비교는 처음부터 직접 만들고 싶지 않은 경우를 위해 완성형 엔진들을 다룹니다. 브라우저에서 Three.js + USDC는 Three.js에서 USD 에셋을 로드하는 방법을 보여 줍니다. itch.io에 출시하는 방법은 뭔가를 만든 뒤의 퍼블리싱을 다룹니다.

각 API를 더 깊이 파고드는 실습 튜토리얼은 이렇습니다.

올바른 기술 스택은 여러분의 게임을 출시시키는 스택입니다. 아는 걸 고르고, 일찍 테스트하고, 나중에 최적화하세요.