---
id: wiki-2026-0508-2026-04-26-skybound-player-sprit
title: Skybound — Player Sprite Path Warning Fix
category: 10_Wiki/Topics
status: verified
canonical_id: self
aliases: [Sprite Path Warning, Phaser Asset Path]
duplicate_of: none
source_trust_level: A
confidence_score: 0.9
verification_status: applied
tags: [skybound, gamedev, asset-loading, phaser, build-config]
raw_sources: []
last_reinforced: 2026-05-10
github_commit: pending
tech_stack:
  language: typescript
  framework: phaser3
---

# Skybound — Player Sprite Path Warning Fix

## 매 한 줄
> **"매 Phaser asset path warning 의 root cause 는 build root vs runtime base href mismatch — `import.meta.env.BASE_URL` 의 사용 으로 의 fix"**. 매 Skybound dev console 의 `Failed to load: assets/airframe/biplane.png` 경고, Vite base config + asset import 의 normalize 으로 해결.

## 매 핵심

### 매 Symptom
- 매 dev (`npm run dev`) 동작, prod build (`npm run build` + serve) 시 404.
- 매 console: `Phaser.Loader.LoaderPlugin: failed to load — file: 'biplane' src: 'assets/airframe/biplane.png'`.
- 매 sprite 의 fallback texture (default green/black checker) 의 표시.

### 매 Root Cause
- 매 Vite 의 default base = `/`, GitHub Pages / sub-path deploy 시 의 `/skybound/` — relative `assets/...` 의 wrong base resolution.
- 매 Phaser preload 의 string-relative path — page URL 기준으로 resolve.

### 매 Fix Strategy
- 매 `import.meta.env.BASE_URL` 의 prefix 적용.
- 매 또는 asset 의 `import` (Vite 의 fingerprint URL 자동 처리).
- 매 또는 `vite.config.ts` 의 `base` 의 deploy target 에 맞게 set.

## 💻 패턴

### Path Helper
```typescript
// src/lib/asset.ts
export function asset(rel: string): string {
  const base = import.meta.env.BASE_URL.replace(/\/$/, '');
  const cleaned = rel.replace(/^\//, '');
  return `${base}/${cleaned}`;
}
```

### Phaser Preload (using helper)
```typescript
import { asset } from '@/lib/asset';

class BootScene extends Phaser.Scene {
  preload() {
    this.load.image('biplane', asset('assets/airframe/biplane.png'));
    this.load.image('jet',     asset('assets/airframe/jet.png'));
    this.load.atlas('vfx',     asset('assets/vfx/vfx.png'), asset('assets/vfx/vfx.json'));
  }
}
```

### Vite-Imported Asset (fingerprinted)
```typescript
// src/scenes/Boot.ts
import biplaneUrl from '@/assets/airframe/biplane.png';
import jetUrl     from '@/assets/airframe/jet.png';

class BootScene extends Phaser.Scene {
  preload() {
    this.load.image('biplane', biplaneUrl);
    this.load.image('jet', jetUrl);
  }
}
```

### Vite Config (sub-path deploy)
```typescript
// vite.config.ts
import { defineConfig } from 'vite';

export default defineConfig({
  base: process.env.DEPLOY_TARGET === 'github-pages' ? '/skybound/' : '/',
  build: {
    assetsDir: 'assets',
  },
});
```

### Manifest Pattern (large asset count)
```typescript
// src/manifest.ts
import { asset } from '@/lib/asset';

export const ASSET_MANIFEST = {
  airframes: {
    biplane: asset('assets/airframe/biplane.png'),
    jet:     asset('assets/airframe/jet.png'),
    ufo:     asset('assets/airframe/ufo.png'),
  },
  vfx: {
    explosion: asset('assets/vfx/explosion.json'),
    sparkle:   asset('assets/vfx/sparkle.json'),
  },
} as const;

// preload
for (const [k, v] of Object.entries(ASSET_MANIFEST.airframes)) {
  this.load.image(k, v);
}
```

### Load Error Diagnostic
```typescript
this.load.on('loaderror', (file: Phaser.Loader.File) => {
  console.error('[asset-load-fail]', {
    key: file.key,
    src: file.src,
    base: import.meta.env.BASE_URL,
    href: window.location.href,
  });
});
```

## 매 결정 기준
| 상황 | Approach |
|---|---|
| Few assets (<50) | `import` each — fingerprint + type-safe |
| Many assets (>50) | Manifest + `asset()` helper |
| Multi-deploy-target | `vite.config base` + helper combo |
| Phaser atlas json+png pair | Both via `asset()` helper |

**기본값**: 매 `import.meta.env.BASE_URL` helper + manifest.

## 🔗 Graph

## 🤖 LLM 활용
**언제**: asset path bug diagnosis, manifest generation, vite config audit.
**언제 X**: bundle size optimization (separate concern).

## ❌ 안티패턴
- **Hardcoded `/assets/...`**: sub-path deploy break — base prefix 의 사용.
- **Relative `./assets/...` everywhere**: page URL drift bug — manifest 의 single source.
- **No `loaderror` handler**: silent fallback texture — diagnostic listener 의 필수.
- **Mixed import + string path**: cache inconsistency — 한 strategy 의 stick.

## 🧪 검증 / 중복
- Verified (Vite docs on `base`, Phaser 3 Loader docs).
- 신뢰도 A.

## 🕓 Changelog
| 날짜 | 변경 |
|---|---|
| 2026-05-08 | Phase 1 |
| 2026-05-10 | Manual cleanup — Vite base + asset manifest fix 정리 |
