이 페이지에서
치수와 픽셀 상세
공유 치수로 비율을 유지하며 모델 크기를 바꾸세요. 눈 같은 작은 무늬는 앵커로 고정해 주변 형상이 바뀌어도 픽셀 크기를 유지할 수 있습니다. 에이전트에게 빌드·수정을 요청할 수 있는 완전한 머리 예제를 제공합니다.
치수 공유하기
module 또는 asset 소스 단위에 design을 선언합니다. 필드는 명시적 타입과 표현식 하나를 가집니다. 로컬은 Design.field, 명시적으로 가져온 공개 design은 alias.Design.field를 사용합니다. 벡터에는 존재하는 축의 .x, .y, .z도 지원합니다.
전방 참조는 허용하지만 순환·중복 이름·네임스페이스 가림·필드 누락·비공개 import·단위 불일치는 거부합니다. 이름 있는 check는 boolean 표현식이며 false면 후보를 거부합니다. 작성한 관계를 표현할 뿐 렌더 모델을 측정하거나 조건을 만족하도록 형상을 움직이지 않습니다.
자주 쓰는 위치는 vec3<unit> 필드로 이름을 붙이세요. 일관된 배치를 도와주지만 자체로 관절을 만들거나 부품을 붙이지는 않습니다.
| 표현식 | 동작 |
|---|---|
texels(length, density) |
음이 아닌 unit 길이와 양의 integer 단위당 픽셀. 결과는 정수 texel이어야 하며 반올림 없음 |
mirror_x(point, plane) |
vec3<unit> 점을 명시적 unit X 평면으로 반사. Y·Z도 지원. 형상·프레임·UV를 반사하지 않음 |
box_origin(anchor, size, alignment) |
성분별 anchor - size * alignment. size는 양의 vec3<unit>, alignment는 각 성분 [0,1]의 vec3<ratio> |
산술은 정확하게 유지합니다. 반 단위 원점은 유효해도 분수 차트 크기는 유효하지 않을 수 있습니다. 형상·스켈레톤 원점·차트 치수·표면 레시피가 같은 design을 사용할 수 있지만 결과 표면은 계약의 차트와 일치해야 합니다. 아틀라스 배치는 명시적이며 계산한 차트 원점에는 완전한 vec2<texel> 필드를 선언하세요.
눈을 키우지 않고 머리 넓히기
완전한 원본을 study.ashfox로 저장하고 ashfox build study.ashfox를 실행하세요. width를 4u에서 6u로 바꾸면 박스·차트 치수가 함께 바뀌지만 두 눈 스탬프는 정확히 1픽셀 너비를 유지합니다. 아틀라스는 명시적이고 범위 안에 남습니다.
ashfox-model 1
asset study {
export design Dimensions {
width: unit = 4u;
height: unit = 4u;
depth: unit = 4u;
size: vec3<unit> = (Dimensions.width, Dimensions.height, Dimensions.depth);
ground: vec3<unit> = (0u, 0u, 0u);
origin: vec3<unit> = box_origin(Dimensions.ground, Dimensions.size, (0.5ratio, 0ratio, 0.5ratio));
chartWidth: texel = texels(Dimensions.width * 2 + Dimensions.depth * 2, 1);
chartHeight: texel = texels(Dimensions.height + Dimensions.depth, 1);
atlasWidth: texel = 64px;
atlasHeight: texel = 32px;
chartOrigin: vec2<texel> = (0px, 0px);
check eyeSpace = Dimensions.width >= 4u;
check fitsAtlasWidth = Dimensions.chartWidth <= Dimensions.atlasWidth;
check fitsAtlasHeight = Dimensions.chartHeight <= Dimensions.atlasHeight;
}
export rig contract HeadRig {
handedness = right;
frame { x = (1, 0, 0); y = (0, 1, 0); z = (0, 0, 1); }
joint root {
parent = none; role = root;
frame { x = (1, 0, 0); y = (0, 1, 0); z = (0, 0, 1); }
channels = (rotation, scale); mirror = none;
}
}
export skeleton HeadSkeleton implements HeadRig {
bind root {
parent-origin = Dimensions.ground;
frame { x = (1, 0, 0); y = (0, 1, 0); z = (0, 0, 1); }
}
}
export surface contract Fur {
atlas { width = Dimensions.atlasWidth; height = Dimensions.atlasHeight; }
chart head box { width = Dimensions.chartWidth; height = Dimensions.chartHeight; coverage = opaque; }
material = opaque;
}
export surface red_fur: Fur {
material = opaque;
texture atlas {
atlas = (Dimensions.atlasWidth, Dimensions.atlasHeight);
background = dark; background-alpha = 255;
palette { dark = #140b0a; coat = (#5a1c10, #b94722, #ef8040); eye = #090707; }
stamp eye { pixels = "e"; e = eye; }
chart head box {
origin = Dimensions.chartOrigin; fill = coat;
face north {
stamp eye { anchor = top_left; offset = (1px, 1px); }
stamp eye { anchor = top_right; offset = (-1px, 1px); }
}
}
grain clustered { seed = 8923; }
tone voxel;
}
}
export component Head {
requires rig skeleton: HeadRig;
requires surface skin: Fur;
bind bone root to skeleton.root;
geometry {
bone root {
cube head {
origin = Dimensions.origin;
size = Dimensions.size;
surface = skin.head;
}
}
}
}
export motion idle for HeadRig {
duration = 2s; fps = 20; loop = loop; rest-relative = true;
track root.rotation {
key 0s = (0deg, 0deg, 0deg) linear;
key 1s = (0deg, 3deg, 0deg) linear;
key 2s = (0deg, 0deg, 0deg) linear;
}
}
export asset study {
settings { density = 16; forward = north; }
skeleton = HeadSkeleton;
motion = idle;
use Head as head { bind skeleton = HeadRig; bind skin = red_fur; };
}
}
고정 크기 무늬와 상세 보호
스탬프는 at = (xpx, ypx) 또는 anchor와 명시적인 부호 있는 offset을 사용합니다. 앵커는 top_left, top, top_right, left, center, right, bottom_left, bottom, bottom_right이며 면 안에서 스탬프 사각형 전체를 정렬합니다. 양의 오프셋은 면 픽셀 좌표의 오른쪽·아래, 음수는 왼쪽·위입니다. 엔진은 스탬프를 확대하지 않습니다. 중앙 정렬에서 남는 픽셀이 홀수면 반올림 방향을 고르지 않고 off-grid로 실패합니다. 모서리 앵커나 치수를 바꿔 해결하세요.
anchor는 사각형 위치만 정합니다. flip = x는 그 안 픽셀을 수평, y는 수직, xy는 양쪽 반사합니다. 생략·none은 원래대로입니다. 배치·크기·투명 칸·보호 사각형의 범위는 유지됩니다.
예를 들어 깊이 8픽셀 머리의 비대칭 3×3 눈은 다음처럼 배치합니다.
stamp eye { pixels = "eee/egg/eee"; e = outline; g = iris; }
chart head box {
origin = (0px, 0px); fill = coat;
face west { stamp eye { anchor = top_left; offset = (1px, 2px); } }
face east { stamp eye { anchor = top_right; offset = (-1px, 2px); flip = x; } }
}
배치 조각이므로 위 완전한 예제처럼 팔레트·대응 차트를 선언해야 합니다. 반대 면의 로컬 수평 방향은 반대입니다. 대칭 앵커는 사각형을, 비대칭 내용 반사는 홍채를 맞춥니다. 양쪽 렌더를 확인하세요. 흉터·윙크처럼 의도적으로 다른 무늬에는 반사를 강요하지 마세요.
선택적 protect = 1px는 투명 점을 포함한 스탬프 사각형과 주변 여백을 이후 voxel tone·grain으로부터 보호합니다. 전체 보호 범위가 면 안에 있어야 합니다. alpha를 칠하거나 차트 커버리지를 바꾸거나 독점 공간을 예약하지 않으며 이후 명시적 스탬프의 덧칠도 막지 않습니다. protect가 없으면 기존 픽셀 보호·래스터 동작을 유지합니다.
큰 색 영역은 surface, 눈·볏은 의도적인 stamp, grain은 램프 안의 제한된 변형에 맡기세요. 실루엣·실제 깊이·부착은 형상에 둡니다. 칠한 무늬를 위해 같은 평면에 형상을 추가하거나 부드러운 곡선을 계단으로 근사하지 마세요.
아틀라스 이동은 각 면의 로컬 픽셀을 유지해야 합니다. 차트 크기 변경은 경계 근처 절차적 grain을 바꿀 수 있으므로 같은 seed만으로 모든 이전 픽셀 유지가 보장되지는 않습니다. nearest 상세와 실제 게임 크기에서 리뷰하세요.
크기 변경 모델 검사하기
원본·변경 모델을 정면과 양쪽에서 비교합니다. 게임 크기로 본 뒤 눈 무늬를 자세히 확인하세요. 눈 픽셀 크기가 유지되고 간격이 넓어진 머리를 따라가며 늘어난 텍스처나 예상치 못한 틈이 없는지 봅니다.
“머리를 넓히되 두 눈의 픽셀 크기와 표정을 보존해라”처럼 요청할 수 있습니다. 관절 근처 부품을 바꾸면 동작도 다시 리뷰하세요.
inspect study.ashfox로 노드 ID를 찾고 inspect study.ashfox --node NODE_ID로 치수·표면을 검사합니다. CLI 관찰을 참고하세요. 측정은 정지 형상을 설명하며 외형·움직이는 부착물 판단에는 렌더 관찰이 계속 필요합니다.