저사양 기기 분류 기준

파일: apps/web/lib/utils.ts PR: #651 최종 수정: 2026-05-22

Android 분류 기준

기준API저사양 조건결합
CPU 코어navigator.hardwareConcurrency≤ 4코어OR
메모리navigator.deviceMemory≤ 4 GB
GPUWEBGL_debug_renderer_infoMali-T830 / T720 / 400

iOS / iPadOS 분류 기준

기준조건판정
물리 코어 ≤ 2hardwareConcurrency ≤ 2즉시 저사양
논리 코어 ≤ 3hardwareConcurrency ≤ 3저사양
iPad 5세대코어=4 + iOS ≤ 16 + 해상도 2048×1536저사양
복합 (코어=4)JS 벤치마크 < 60 FPS 또는 (iOS ≤ 16 + 구형 해상도)저사양

데스크탑 / 노트북 PPI-975 추가

1

리소스 캐싱 전 initLowPerformanceDevice() await 호출

결과는 모듈 레벨 캐시에 저장 — 이후 동기 호출은 캐시 반환

2

MediaCapabilities.decodingInfo() 로 MP4 H.264 720p 디코딩 실측

type: "file" · contentType: "video/mp4; codecs=avc1.42E01E" · 1280×720 · 30fps · 1Mbps

3

!result.smooth && !result.powerEfficient → 저사양

powerEfficient=true(하드웨어 가속 중)이면 smooth=false여도 고사양으로 판정

판정 기준 상세

smoothpowerEfficient판정근거
truetrue고사양하드웨어 가속 + 부드러운 재생
falsetrue고사양하드웨어 가속 중 — Chrome 첫 쿼리 보수적 판정
falsefalse저사양소프트웨어 디코딩 + 끊김 예상

리소스 선택 결과

기기저사양 판정비디오 리소스조건
Android / iOS (저사양)true480ps3KeyProcessed480p 존재 시
Android / iOS (고사양)false720ps3KeyProcessed 또는 원본
노트북/데스크탑 (저사양)true480psmooth=false AND powerEfficient=false
노트북/데스크탑 (고사양)false720psmooth=true OR powerEfficient=true

핵심 코드

// apps/web/lib/utils.ts

async function _checkDesktopDecodingCapability(): Promise<boolean> {
  if (!("mediaCapabilities" in navigator)) return false;
  try {
    const result = await navigator.mediaCapabilities.decodingInfo({
      type: "file",
      video: { contentType: "video/mp4; codecs=avc1.42E01E",
               width: 1280, height: 720, bitrate: 1_000_000, framerate: 30 },
    });
    console.log("[LowPerf] decodingInfo:", {
      supported: result.supported, smooth: result.smooth, powerEfficient: result.powerEfficient,
    });
    // powerEfficient=true(하드웨어 가속)이면 고사양으로 판정
    return !result.smooth && !result.powerEfficient;
  } catch { return false; }
}

export async function initLowPerformanceDevice(): Promise<boolean> {
  if (_lowPerfCache !== null) return _lowPerfCache;
  if (!_lowPerfPromise) {
    _lowPerfPromise = (async () => {
      const syncResult = _computeSyncLowPerf(); // Android/iOS
      const isDesktop =
        !/Android|iPad|iPhone|iPod/i.test(navigator.userAgent) &&
        !(navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1);
      const result =
        syncResult || (isDesktop && await _checkDesktopDecodingCapability());
      _lowPerfCache = result;
      console.log("[LowPerf] result:", { isLowPerformanceDevice: result,
        ua: navigator.userAgent, platform: navigator.platform,
        hardwareConcurrency: navigator.hardwareConcurrency,
        deviceMemory: (navigator as any).deviceMemory ?? "unknown" });
      return result;
    })();
  }
  return _lowPerfPromise;
}