이 페이지에서
엔진 중립적인 게임 에셋
Minecraft 팩은 여러 전달 대상 중 하나입니다. 일반 복셀·로우폴리 게임은 packs[].format: game_assets로 GLB 모델, PNG 스프라이트, WAV·OGG 변형, 엔진 중립적인 런타임 매니페스트 assets.json을 생성합니다. 게임은 빌드 경로를 추측하지 않고 설정된 ID로 에셋을 찾습니다.
같은 .ashfox 원본과 이름 있는 exports를 한 번의 원자적 빌드에서 여러 게임 팩·Minecraft 팩에 전달할 수 있습니다. 새 소스 언어를 도입하거나 컴파일러를 특정 엔진에 결합하지 않습니다.
설정
완전한 게임 프로젝트를 풀면 examples/game-assets/.ashfoxworkspace에 설정이 있습니다. 팩 선언은 다음과 같습니다.
{
"name": "voxel_game",
"format": "game_assets",
"directory": "dist/game",
"archive": true,
"audio": "wav",
"unitsPerMeter": 1,
"pixelsPerUnit": 16,
"spriteFilter": "nearest",
"assets": [
{ "id": "creature.griffin", "source": "griffin", "path": "models/griffin" },
{ "id": "item.iron_sword", "source": "iron_sword", "path": "sprites/items" },
{ "id": "sfx.claw_hit", "source": "claw_hit", "path": "audio/claw_hit" }
]
}
표시한 필드는 모두 필수입니다. source는 export 이름, id는 런타임 ID, path는 패키지 안 상대 디렉터리입니다. 패키지 안 ID는 고유해야 합니다. 바이트가 같아도 파일·폴더 충돌과 중복 출력 경로는 실패합니다. 경로는 팩 밖으로 나가거나 예약 assets.json을 차지할 수 없습니다. 연결은 glb, png, wav export만 받으며 Minecraft 전용 파일 트리를 일반 모델로 해석하지 않습니다.
audio: wav에는 외부 인코더가 필요 없습니다. audio: ogg는 Java 팩과 같은 제한된 FFmpeg Vorbis 어댑터로 사운드를 변환합니다. 사운드가 없으면 FFmpeg를 실행하지 않습니다. WAV 원본 export는 별도로 유지됩니다. 항상 폴더를 출력하며 archive: true는 그 파일만 포함하고 루트에 assets.json을 두는 안정적인 ZIP을 추가합니다.
GLB 이식성과 임포트 설정
CLI GLB 기본값 encoding: portable은 표준 부동소수점 정점 속성을 저장하고 Meshopt 압축을 생략해 압축·메시 양자화 확장을 요구하지 않습니다. 텍스처·메시·재질·스킨·애니메이션은 GLB 하나에 들어갑니다. 정적 장면에는 idle이 필요 없지만 형상·텍스처 커버리지·작성한 애니메이션은 검증합니다. Minecraft 액터 대상의 idle 요건은 유지됩니다.
더 작은 기존 인코딩을 명시적으로 선택할 수 있습니다.
{
"name": "griffin",
"entry": { "packageName": "workbench", "entryName": "griffin" },
"format": "glb",
"encoding": "optimized",
"directory": "dist/models"
}
런타임 매니페스트는 실제 requiredExtensions를 기록합니다. optimized는 대상 임포터에서 Meshopt·메시 양자화 지원이 필요할 수 있으므로 확인 전에는 portable을 사용하세요.
GLB는 기존 glTF exporter와 같이 원본 u 하나를 1/16미터로 인코딩합니다. coordinateSystem: gltf2는 인코딩된 좌표계입니다. 축·좌우손 좌표계 변환은 엔진의 GLB 임포터에 맡기세요. unitsPerMeter는 추가로 적용된 변환이 아닌 게임 임포트 힌트이며, 임포터가 처리하지 않으면 한 번 적용합니다. 미터당 엔진 단위 하나는 1, 센티미터 단위는 100을 사용합니다.
스프라이트 메타데이터는 픽셀 크기, pixelsPerUnit, filter를 가집니다. 단위당 16픽셀이면 16픽셀 스프라이트의 너비는 게임 단위 하나입니다. nearest는 선명한 픽셀 가장자리, linear는 보간을 요청합니다. 임포터 힌트이며 GLB 샘플러를 수정하거나 엔진 프로젝트를 암묵적으로 설정하지 않습니다.
런타임 매니페스트
반환된 팩 대상에는 다음이 들어갑니다.
game-assets/
assets.json
models/griffin/griffin.glb
sprites/items/iron_sword.png
audio/claw_hit/<variant>.wav
voxel_game.zip
assets.json은 format: ashfox-game-assets, version: 1, ID순 assets를 가집니다. 파일 경로는 매니페스트 폴더 기준입니다. 게임 폴더에는 절대 경로·컴파일 영수증·Minecraft 등록 파일이 없습니다. 영수증은 정식 빌드 번들에 남습니다.
| 종류 | 런타임 필드 |
|---|---|
model |
model 경로, glTF 좌표 규칙, unitsPerMeter, 필수 확장, 클립 이름·길이 |
sprite |
image 경로, 너비·높이, 단위당 픽셀, 필터 |
sound |
코덱, 파일 경로·의도 길이·샘플률·채널 수를 가진 이름 있는 변형 |
모든 항목에는 id와 정확한 바이트 길이·SHA-256을 기록한 files도 있습니다. OGG 길이는 원본의 의도 길이이며 디코딩 중 작은 인코더 패딩이 더해지거나 빠질 수 있습니다. 인코딩 어댑터가 이를 검사합니다.
웹 게임은 자체 GLB 로더에 전달할 파일을 다음처럼 찾습니다.
const manifestUrl = new URL('./game-assets/assets.json', document.baseURI);
const response = await fetch(manifestUrl);
if (!response.ok) throw new Error(`Asset manifest: HTTP ${response.status}`);
const manifest = await response.json();
if (manifest.format !== 'ashfox-game-assets' || manifest.version !== 1) {
throw new Error('Unsupported asset manifest');
}
const griffin = manifest.assets.find(asset => asset.id === 'creature.griffin');
if (!griffin || griffin.kind !== 'model') throw new Error('Missing griffin model');
const glbUrl = new URL(griffin.model, manifestUrl);
// Pass glbUrl to your engine's GLB importer; use griffin.clips for animation names.
모델·애니메이션·아이템·사운드를 보여주는 완전한 로더는 웹 게임 예제를 따라가세요.
검증과 경계
npx --no-install ashfox build .ashfoxworkspace --json
npx --no-install ashfox verify dist/build --json
반환된 팩 폴더를 사용하거나 ZIP을 게임 에셋 폴더에 풉니다. assets.json을 읽고 ID를 찾으며 위 메타데이터로 임포터를 설정하세요. 복사 전에 정식 빌드를 검증하고 게임 빌드 전체에서 선택 번들을 고정합니다. 자동화를 참고하세요.
팩은 렌더·오디오 에셋과 임포트 메타데이터를 담습니다. 복셀 청크 저장, 지형 메시, 충돌체, 게임 동작 정의, 엔진 프리팹·장면, 엔진별 런타임 로더는 생성하지 않습니다. 대상 엔진은 GLB·PNG·오디오 임포트를 지원해야 합니다. 포맷 테스트가 특정 엔진의 렌더링을 인증하지는 않습니다.