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

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

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

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

게임 화면에 fps 를 띄우는 열 줄짜리 코드

2026년 10월 25일 · 기술 · English

지난 글에서 아이패드에서만 느린 게임을 고친 이야기를 적었다. 원인을 찾을 수 있었던 건 화면에 fps 를 찍어 두었기 때문이다. 느리다는 느낌만으로는 고쳐도 나아졌는지 알 수 없고, 기기를 바꿔 비교할 수도 없다. 이 글에서는 그 표시를 어떻게 만들었는지, 그리고 아이패드에서 숫자를 읽기까지 겪은 일을 적는다.

fps 는 1초에 화면을 몇 번 새로 그렸는지다. 브라우저에서 게임 루프를 돌릴 때는 보통 requestAnimationFrame 에 그리기 함수를 등록한다. 브라우저는 화면을 갱신하기 직전에 이 함수를 부르면서 현재 시각을 인자로 넘겨 준다. 그러니 이 함수가 불린 횟수를 세고, 1초가 지날 때마다 그 횟수를 시간으로 나누면 된다.

게임 루프를 이미 쓰고 있다면 루프 안에서 한 줄을 호출하는 것으로 끝난다. 설명을 위해 줄인 예시는 이렇다.

let frames = 0;
let since = performance.now();
let label = null;

function countFrame(now) {
  frames++;
  if (now - since < 1000) return;

  const fps = (frames * 1000) / (now - since);
  if (!label) {
    label = document.createElement('div');
    label.style.cssText = 'position:absolute;top:6px;left:50%;translate:-50% 0;' +
      'padding:2px 6px;border-radius:6px;background:rgba(0,0,0,.6);color:#fff;font:700 13px system-ui;pointer-events:none';
    document.body.append(label);
  }
  label.textContent = fps.toFixed(1) + 'fps';
  frames = 0;
  since = now;
}

function loop(now) {
  update();
  draw();
  countFrame(now);
  requestAnimationFrame(loop);
}
requestAnimationFrame(loop);

1초를 기다렸다가 평균을 내는 이유는 프레임마다 값이 출렁이기 때문이다. 한 프레임의 간격으로 계산하면 숫자가 계속 바뀌어 읽을 수 없다. 표시 칸은 처음 한 번만 만들고 이후에는 글자만 바꾼다. pointer-events: none 을 주어 이 표시가 게임 조작을 가로채지 않게 한다.

처음에는 구름 점프에만 이 코드를 넣었다. 그런데 같은 도구를 쓰는 다른 게임에도 같은 증상이 있었다. 게임마다 코드를 복사해 넣는 대신 모든 게임이 쓰는 공통 루프로 옮겼다. 켜 두지 않은 게임은 이 코드를 한 줄도 실행하지 않는다.

켜는 방법은 주소 뒤에 ?debug=fps 를 붙이는 것이다. 이 방식은 실제 사이트에서도 쓸 수 있다는 점이 컸다. 아이패드나 아이폰에서 주소만 바꿔 열면 되므로 별도 빌드가 필요 없고, 이 표시는 기록이나 점수에 영향을 주지 않도록 보기만 하게 만들었다.

fps 옆에 캔버스의 픽셀 크기(width x height)도 같이 찍는다. 같은 화면이라도 기기마다 캔버스의 실제 픽셀 수가 다르고, 고해상도 화면에서는 그리는 픽셀이 훨씬 많다. 대시 런이 느렸던 실제 아이패드의 캔버스는 2732×1784 픽셀이었다. 이 숫자가 같이 보여야 느린 이유가 그리는 양 때문인지 그리는 방식 때문인지 구분할 수 있다. 캔버스 크기를 줄여서 비교하는 lowres 값도 같은 주소 값에 붙여 쓸 수 있게 했다.

시뮬레이터를 준비하는 데 든 것

실제 아이패드가 늘 손에 있는 것은 아니라서 Xcode 의 iOS 시뮬레이터를 쓰기로 했다. 시뮬레이터는 맥에서 아이패드를 흉내 내는 프로그램이다. 안에서 돌아가는 사파리는 실제 기기와 같은 엔진이다. 처음 준비할 때 걸린 것은 iOS 용 시뮬레이터 플랫폼을 내려받는 일이었다. 용량이 약 8GB 였다. 받고 나서는 아이패드 기기를 하나 만들고 켜는 명령을 차례로 실행한다.

xcodebuild -downloadPlatform iOS
xcrun simctl create "iPad A16 test" com.apple.CoreSimulator.SimDeviceType.iPad-A16 com.apple.CoreSimulator.SimRuntime.iOS-26-1
xcrun simctl boot {device id}

xcrun simctl 은 터미널에서 시뮬레이터를 조작하는 도구다. 주소를 열 때는 xcrun simctl openurl 을 쓰는데, 처음 실행하면 시간 초과 오류가 나는데도 사파리는 열린다. 오류 메시지만 보면 실패한 것처럼 보여서 헷갈리기 쉽다. 맥에서 띄운 개발 서버를 시뮬레이터가 그대로 볼 수 있어서, 코드를 고치고 새로고침만 하면 된다.

시뮬레이터 화면의 숫자는 스크린샷을 찍어서 읽는다. 게임이 열아홉 개가 되니 하나씩 열어 보는 일이 번거로워서, 스크린샷의 글자를 읽는 스크립트를 만들었다. macOS 에는 이미지 속 글자를 읽어 주는 문자 인식 기능(Vision)이 있어서 그것을 불러 쓴다. 게임마다 주소를 열고 화면을 찍고 숫자를 읽어 표로 정리한다.

시뮬레이터의 스크린샷은 기기를 가로로 돌려도 항상 세로 픽셀로 나온다. 그래서 글자가 옆으로 누운 채 찍힐 수 있다. 사진을 0, 90, 180, 270도로 돌려 가며 읽도록 했다. 게임이 세로나 가로 전용이라 기기를 돌려 달라는 화면이 뜨면 시뮬레이터를 직접 돌려서 다시 읽게 했다. 이렇게 처음 잰 결과는 열아홉 개 중 열여덟 개가 53~60fps 였다.

지난 글에서 적은 것처럼 시뮬레이터는 맥의 그래픽 칩을 쓴다. 시뮬레이터에서 60fps 가 나와도 실제 아이패드에서는 11fps 였다. 그래서 시뮬레이터 숫자는 방향을 잡는 데 쓰고, 마지막 확인은 실제 기기에서 같은 주소로 한다. 실제 사이트에서도 이 표시가 켜지니, 배포한 뒤 아이패드 주소창에 ?debug=fps 만 붙이면 같은 숫자를 볼 수 있다.

fps 표시를 하나 만들어 두면 성능 문제가 감각에서 숫자로 바뀐다. 코드는 짧지만 이것이 없었다면 아이패드에서 느린 이유를 찾는 데 훨씬 오래 걸렸을 것이다.

참고한 문서

이 글과 관련된 게임

구름 점프구름을 밟고 통통 튀어 하늘 높이 올라가세요. 회색 구름은 밟으면 흩어지고, 천둥구름은 위에서 밟아야 해요! 해 보기

다른 글

홈 화면에 추가하기

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

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