본문으로 건너뛰기

합성 값 타입 — 벡터 · 회전 · 색

문서 목록으로

성분이 여러 개인 값을 셀 하나에 적는 표기와, 그것을 형식 변경 없이 싣는 설계입니다. vec2i·vec3f·quat·color 같은 이름을 타입 행에 두고, 셀에는 (111, 222)·#3366CC·red를 적습니다.

핵심은 한 줄입니다. 합성 타입은 셀 표기이고, 파싱이 끝나면 레코드로 접힙니다. 와이어도 13개 생성기도 익스포터도 바뀌지 않습니다 — 레코드는 이미 전부 지원하는 형태이기 때문입니다.


1. 문제 — 성분이 여러 개인 값의 자리 부재

좌표 하나를 시트에 적으려면 지금은 컬럼 3개가 필요합니다. Pos.X·Pos.Y·Pos.Z로 적으면 중첩 필드가 레코드로 접어 주므로 소비 측의 형태는 나쁘지 않습니다. 비용은 그 앞쪽에 있습니다.

비용내용
시트성분마다 컬럼 하나이고, 헤더 4행이 성분마다 반복됩니다. 좌표 컬럼 20개는 실제 컬럼 60개입니다
의도float 컬럼 3개는 좌표인지 무관한 수치 3개인지 구별되지 않습니다. 타입 행은 시트를 읽는 사람이 보는 유일한 자리입니다
색의 표기#3366CC를 적을 자리가 없습니다. 지금 그런 값은 bigint0x3366CC로 들어가고, 성분으로 나누는 것은 소비 측의 일입니다
이름 있는 값redone처럼 팀과 업계가 이미 쓰는 이름을 셀에 적을 방법이 없습니다

2. 결정 — 타입 추가가 아니라 셀 표기

결정. 합성 타입은 파싱이 지속되는 동안만 타입이고, 셀이 값이 된 뒤에는 레코드입니다.

비트셋이 같은 판단을 한 자리이고, 근거도 같습니다. ValueType 멤버는 추가되지만 접히기 전까지만 존재합니다. 새 멤버가 다운스트림에 도달하면 조회 표·switch·SQL 스키마·13개 생성기·이력에 걸쳐 손이 가고, 실측 — 이 저장소에서 ValueType.Uuid를 언급하는 파일은 27개이며 그중 default가 있는 switch는 새 멤버를 모른 채 틀린 결과를 산출합니다. 접기는 그 100곳을 0곳으로 만듭니다.

접는 대상이 bitset과 다른 점은 접힌 뒤의 형태입니다.

타입접힌 뒤
bitsetInt64 하나 — 스칼라
합성 타입레코드 하나 — 성분마다 멤버

레코드를 고르는 것이 성립하는 이유는 그 형태가 이미 완성되어 있기 때문입니다. 모든 언어와 json·binary가 레코드를 지원하고, 와이어는 레코드를 원래 멤버마다 컬럼 하나로 싣습니다 (중첩 필드). 성분마다 컬럼 하나는 이 도구가 이미 쓰고 있는 저장 형태입니다.

접기의 시점

시점타입
타입 행을 읽을 때합성 타입 — 이름 표가 받습니다
셀을 읽을 때합성 타입 — 4절의 표기 규격이 여기에서 적용됩니다
확장 직후컬럼 N개의 레코드 그룹
와이어·13개 생성기·익스포터·이력레코드

Field.TypeNamevec3f로 남습니다 — 시트에 그렇게 적혀 있고, 그 컬럼에 대한 진단이 그 이름으로 지시해야 하기 때문입니다.

3. 타입 목록

이름성분성분 타입빈 값
vec2i · vec3i · vec4iX Y Z Wint0
vec2f · vec3f · vec4fX Y Z Wfloat0
eulerX Y Z — 각도(도)float0
quatX Y Z Wfloat(0, 0, 0, 1) — 항등
axisangleX Y Z Angle — 각도(도)float(0, 0, 1, 0)
colorR G B Afloat(0, 0, 0, 0)
color32R G B Aint0~255(0, 0, 0, 0)

성분 이름은 그대로 생성 코드의 멤버 이름이 됩니다.

빈 값이 0이 아닌 둘. quat(0,0,0,0)은 회전이 아니므로 항등 회전을 빈 값으로 둡니다. axisangle은 각이 0이면 축이 무엇이든 회전이 없고, 축은 영벡터일 수 없으므로 Z를 세웁니다. 색 2종의 빈 값을 불투명 검정이 아니라 투명으로 두는 것은, 적지 않은 칸이 화면에 검은 사각형으로 나타나는 것보다 나타나지 않는 편이 오해가 적기 때문입니다.

이름에 성분 타입을 적는 이유

vec2가 아니라 vec2i·vec2f입니다. 접미를 생략하면 성분이 정수인지 실수인지가 시트가 아니라 도구의 기본값에 달리고, 그 기본값은 시트를 읽는 사람에게 보이지 않습니다. bigintbitset을 가른 것과 같은 기준입니다 — 타입 행은 무엇이 담기는지가 적히는 자리입니다.

4. 표기

4.1 튜플

(111, 222) 111, 222 (1.5,-2.5,0)
규칙내용
성분 구분자쉼표 고정
괄호생략 가능. 8절 ①의 함정이 괄호 쪽에 있으므로 강제하지 않습니다
공백성분 앞뒤의 공백은 무시합니다
성분 개수타입의 개수와 정확히 일치해야 합니다. 색 2종만 예외로 알파를 생략할 수 있습니다
성분의 표기그 성분 타입의 표기 그대로입니다. int 성분은 0x·0b 리터럴과 천 단위 구분자를 받습니다

성분 개수가 어긋나면 몇 개를 기대했는지와 함께 그 셀을 가리켜 거부합니다. 개수는 줄이거나 늘려 받지 않습니다vec3f에 성분 2개를 받고 Z를 0으로 두는 것은 적지 않은 것과 0을 적은 것을 구별하지 못하게 만듭니다.

4.2 기호 리터럴

리터럴해당 타입
zero벡터 6종성분 전부 0
one벡터 6종성분 전부 1
identityquat · axisangle3절의 빈 값

색 2종은 zero·one을 받지 않습니다. one이 「성분 전부 1」인지 「흰색」인지가 colorcolor32에서 갈리기 때문입니다 — color32에서 전자는 거의 검정이고 후자는 흰색입니다. 색에는 이미 모호하지 않은 이름이 있으므로 그쪽을 씁니다: black·white·transparent.

한정 표기 vec2i.one도 받습니다. 접두가 컬럼의 타입과 다르면 오류입니다vec2i 컬럼의 vec3f.one은 성분 개수가 우연히 맞을 수 없는 종류의 착오이고, 조용히 받으면 잘못된 컬럼을 고쳤다는 사실이 드러나지 않습니다.

대소문자는 무시합니다. One·ONE·Vector2i.one이 모두 같습니다.

up·forward·right주지 않습니다. 5절에 이유가 있습니다.

4.3 색 — colorcolor32

표기는 공통입니다.

표기해석
튜플 3성분(1.0, 0.5, 0.25) · (255, 128, 64)RGB, 알파는 불투명
튜플 4성분(1.0, 0.5, 0.25, 0.5) · (255, 128, 64, 128)RGBA
# 3·4자리#39C · #39CF각 자리를 두 번 반복 — #3399CC
# 6·8자리#3366CC · #3366CCFF8비트 성분
0x 6·8자리0x3366CC#과 동일
이름red · cornflowerblue4.4의 팔레트
한정 이름material.blue.5004.4의 팔레트

갈라지는 것은 성분입니다.

구분colorcolor32
성분 타입floatint
튜플의 성분실수 — 0.5정수 0~255128
#3366CC255로 나눕니다그대로
알파 생략1.0255
범위 검사없음 — 1을 넘는 값은 HDR 색입니다있음0~255 밖은 오류
해당하는 자리계산되는 색, 밝기가 1을 넘는 값피커·hex·팔레트에서 온 색
엔진의 짝Unity Color · Unreal FLinearColorUnity Color32 · Unreal FColor

color32 컬럼의 소수점은 거부합니다. (1.0, 1.0, 1.0)color의 흰색이고 color32에서는 「1/255 3개」로도 읽히는 표기입니다. 소수점이 있으면 그 컬럼은 color32가 아니고, 거부 메시지가 color를 지시합니다. 비트셋1.0을 거부한 것과 같은 기준입니다 — 소수부가 0이면 봐주는 것이 모호함의 시작입니다.

정수 하나로 접지 않습니다. 0xFF3366CCint 컬럼 하나로 싣는 편이 컬럼 4개보다 작아 보이지만, 두 가지를 잃습니다 — 성분마다 이름이 붙은 API와, 성분 단위의 이력 diff입니다. 크기 쪽은 비트폭 패킹이 이미 해결합니다: 0~255 범위의 정수 컬럼은 폭 8로 접히므로 성분 4개가 로우당 4바이트이고, 팔레트에서 온 색은 반복되므로 사전 인코딩이 다시 줄입니다.

색 공간은 sRGB입니다. 시트에 적히는 색은 디자이너의 피커와 hex 코드에서 오고 그것들이 sRGB이기 때문입니다. 리니어 변환은 하지 않습니다 — 변환해서 실으면 무엇이 적혀 있었는지 되돌릴 수 없고, 어느 공간이 필요한지는 렌더러의 사정입니다. 이것이 color를 리니어로 규정하지 않는 이유이기도 합니다: 두 타입의 차이는 성분의 정밀도이지 색 공간이 아닙니다.

4.4 팔레트

구분내용
내장css 하나 — CSS Color Module Level 4의 이름 색 148개와 transparent 키워드
추가recipe 최상위의 Palettes 항목이 이름마다 파일을 지정합니다. 코드가 아니라 데이터입니다
css의 교체거부합니다. 빈 이름이 조회되는 자리이므로, 바꾸면 이미 변환되는 시트의 red가 달라집니다
접두 없는 이름css에서만 조회합니다
접두 있는 이름해당 팔레트에서만 조회합니다

접두 없는 이름을 css로 한정하므로 팔레트끼리 이름이 충돌할 수 없습니다. 팔레트를 추가해도 기존 시트의 red가 다른 색이 되는 일이 없고, 그것이 이 규칙의 목적입니다.

선언이 소스 항목이 아니라 recipe 최상위에 있는 것도 같은 이유입니다. 한 빌드 안에서 색 이름은 어느 워크북에서 왔든 같은 색이어야 하고, 소스마다 팔레트를 두면 그 보장이 없어집니다.

material·tailwind처럼 널리 쓰이는 팔레트는 저장소가 데이터 파일로 동봉할 수 있습니다. 라이선스가 재배포를 허용하는 것에 한정하고, Pantone·RAL은 담지 않습니다 — 상표와 라이선스가 걸린 색 체계입니다.

팔레트 항목은 8비트 sRGB 하나로 보관합니다. 팔레트의 출처가 hex 코드이므로 그것이 원본에 가장 가까운 표현이고, color32는 그대로, color는 255로 나누어 받습니다. 팔레트를 실수로 보관하면 color32 쪽에서 반올림이 한 번 더 발생합니다.

4.5 배열과 옵셔널

형태지원
vec2f?됩니다. 빈 칸은 3절의 빈 값입니다
Slot1.Pos: vec3f됩니다 — 별도 작업 없이. 확장 결과가 Slot1.Pos.X이고, 그것은 이미 지원되는 「멤버가 레코드인 레코드의 배열」입니다
Pos1: vec2f · Pos2: vec2f레코드 2개입니다 — 배열이 아닙니다. 아래
vec2f[] — 한 셀의 가변 배열담지 않습니다. 9절

확장은 이름의 숫자를 읽지 않습니다. Pos1은 그대로 Pos1이라는 그룹이 되고, Pos2는 별개의 그룹이 됩니다. 숫자가 배열을 뜻하는지는 레이아웃의 판단이고 그 판단이 내려지는 자리는 하나여야 하기 때문입니다 — 코어가 다시 자릿수를 읽으면 같은 질문에 대한 두 번째 답이 생깁니다(Field.NamePath가 파생이 아니라 실려 다니는 이유와 같습니다). 배열을 뜻하는 시트는 그룹 표기로 적고, 확장은 그 위에 성분을 한 단계 더 얹습니다.

vec2f?는 존재 여부를 와이어에 담지 않습니다. 레코드의 멤버는 정의상 nullable이 아니고 (WireColumnIsNullable = false), 그 결정의 근거는 「Id는 있는데 Count는 없다」가 레코드의 API에 없는 형태라는 것입니다. 결과로 합성 컬럼의 빈 칸과 빈 값을 적은 칸이 파일에서 구별되지 않습니다. 필요해지면 옵셔널 필드의 presence 비트맵을 그룹 단위로 확장하는 별도 개정입니다.

5. 규약이 필요한 것 — 주지 않는 이름

up·forward·right·back거부합니다. 값이 엔진마다 다르기 때문입니다.

엔진위쪽앞쪽손 방향
Unity+Y+Z왼손
Unreal+Z+X왼손
glTF · 다수의 DCC+Y-Z오른손

코어가 하나를 고르면 나머지 규약을 쓰는 프로젝트에서 값이 조용히 틀립니다. 성분 3개가 전부 0과 1이라 값 대조로도 드러나지 않는 종류입니다. 거부 메시지는 튜플로 적을 것을 지시합니다.

같은 이유로 euler의 회전 순서를 규정하지 않습니다. 이 타입이 담는 것은 축마다 각도 하나씩 3개이고, 그것을 어떤 순서로 합성하는지는 소비 측의 규약입니다. 문서에 그렇게 적고, 코어는 순서를 가정하는 계산을 하지 않습니다.

각도의 단위는 도로 고정합니다. 라디안 표기를 두지 않는 것은 시트에 적히는 각도가 도이고, 표기가 둘이면 어느 쪽인지 셀만 보고 알 수 없기 때문입니다.

규약을 recipe가 선언하면 이 이름들을 줄 수 있습니다. 축 규약을 선언하는 자리를 만드는 것은 별도 개정이고, 그 자리가 생기기 전에는 이름을 주지 않습니다.

6. 모델과 저장

6.1 확장

합성 컬럼 하나가 컬럼 N개로 바뀝니다. Pos: vec3fPos.X·Pos.Y·Pos.Z가 되고, 그 셋은 중첩 필드가 접는 것과 완전히 같은 컬럼입니다.

항목내용
자리ModelCooker.ExpandCompositeColumns 한 곳 — 레이아웃 파서는 무변경입니다
시점ParseRawModel 직후, 비트셋 접기와 나란히
하는 일필드를 N개로 교체하고 NamePath에 성분 이름을 덧붙입니다. 각 로우에 셀 N개를 삽입하고 Field.Index를 다시 매깁니다
HasValue원래 셀의 것을 성분 전부가 물려받습니다. 한 셀에서 왔으므로 답도 하나입니다

레이아웃이 아니라 쿠커에 두는 것이 판단입니다. 파서 안에서 하면 3개 파서에 같은 호출을 넣어야 하고, 넣는 것을 빠뜨린 레이아웃은 합성 타입을 그것을 모르는 코드로 넘깁니다. 쿠커에 두면 모든 레이아웃이 이 타입을 그냥 갖게 됩니다.

대신 태그를 다시 매깁니다. 레이아웃은 데이터를 읽은 직후 AssignTags를 호출하고, 그 시점의 합성 컬럼은 아직 컬럼 하나이므로 서수 태그가 어긋나기 때문입니다. 바뀐 테이블에 한해 태그를 지우고 다시 할당합니다 — 서수 태그는 자리 번호이지 이름이 아니므로 잃을 것이 없고, 태그를 시트에 적은 테이블은 아래에서 이미 거부됩니다.

6.1.1 합성 컬럼이 지닐 수 없는 선언 셋

세 가지를 타입 행의 이름과 함께 거부합니다. 셋 다 확장 뒤에도 결국 걸리지만, 그때는 컬럼이 Pos.X이고 보고가 시트에 없는 이름을 부르게 됩니다.

선언거부하는 이유
* 인덱스키는 값 하나입니다. 6.3
@N 태그합성 컬럼은 와이어 컬럼 N개가 되므로 태그도 N개가 필요합니다. 하나만 적힌 것을 N개로 늘리면 적지 않은 태그를 조용히 가져가게 됩니다. 태그를 쓰는 테이블은 성분을 컬럼으로 적습니다
컬럼 제약범위가 성분에 대한 것인지 크기에 대한 것인지 정해지지 않았습니다. 9절

파생 뷰를 무효화해야 합니다. Table.SerialFieldsTable.WireColumns는 필드 목록에 대한 캐시이고 필드의 타입을 스냅샷합니다. 비트셋 접기가 같은 자리에서 걸렸던 곳입니다 (그 기록).

불변식 — 요리가 끝난 모델에 합성 타입 필드가 남아 있으면 안 됩니다. 확장을 호출하지 않은 레이아웃이 있으면 그 사실이 검증에서 드러나야 하고, 진단 없이 다운스트림에 도달하면 생성기가 알 수 없는 타입에서 멈춥니다.

6.2 바뀌지 않는 것

항목
형식 버전변경 없음
13개 리더변경 없음
JSON{"x": 1, "y": 2} — 레코드와 동일
SQL 스키마성분마다 컬럼 (Pos_X·Pos_Y) — 레코드와 동일
이력 diff성분 단위. 좌표 하나만 움직인 로우가 그 성분으로 표시됩니다

이 문서의 1단계가 성립하는지를 판정하는 자리가 여기입니다. 같은 데이터를 Pos: vec3f로 적은 시트와 Pos.X·Pos.Y·Pos.Z로 적은 시트에서 각각 내보내 바이트가 같아야 합니다. 10절의 게이트입니다.

6.3 인덱스 키

합성 컬럼은 인덱스가 될 수 없습니다. 확장 뒤에는 레코드 그룹이라 자동으로 거부되지만, 그 거부이 「레코드는 키가 아니다」로 보고되면 시트를 적은 사람이 무엇을 고쳐야 하는지 알기 어렵습니다. 확장 전에, 그 컬럼의 타입 이름과 함께 거부합니다.

7. 생성 코드의 정체성 — 이 개정이 끝내지 않는 것

1단계의 산출은 컬럼마다 별도의 구조체입니다. C#이라면 Record.PosEntry { X, Y, Z }이고, 생성기 관점에서 이것은 보통의 레코드 그룹입니다.

그래서 남는 것이 하나 있습니다. vec3f 컬럼이 50개면 서로 다른 구조체 50개이고, 어느 것도 엔진의 벡터 타입이 아닙니다. 소비 측은 여전히 성분을 옮겨 담는 코드를 씁니다 — 1절이 지적한 비용 4개 중 마지막 것은 1단계에서 줄어들지 않습니다.

단계를 셋으로 나눕니다.

단계산출비용
1컬럼마다 레코드 구조체생성기 무변경. 이 문서가 규정하는 범위입니다
2언어별 공용 타입 — Vector3f·Color·Color32lib/<언어>/tabbit에 손으로 13번, 프로파일에 타입 이름과 생성자 패턴
3타깃별 바인딩 — UnityEngine.Vector3·FVectorrecipe의 타깃 섹션에 타입 이름과 생성자 패턴을 적는 항목 하나

색을 2종으로 가른 것이 3단계에서 값을 냅니다. 주요 엔진이 같은 자리에서 같은 쌍을 두고 있으므로(Color/Color32, FLinearColor/FColor) 바인딩이 1:1입니다. 색이 1종이면 그 recipe 항목이 어느 쪽으로 가야 하는지를 시트가 말해 주지 못합니다.

와이어는 세 단계에서 모두 같습니다. 성분마다 컬럼 하나이고, 바뀌는 것은 그 성분들을 어느 타입에 담아 돌려주는지뿐입니다. 단계 사이에 형식 변경이 없다는 뜻이고, 1단계를 먼저 내보내도 2·3단계가 기존 파일을 무효화하지 않습니다.

엔진 이름은 recipe에만 둡니다. 3단계가 recipe 항목인 것은 편의가 아니라 요건입니다 — UnityEngine.Vector3가 코어에 들어가면 그 이름을 지우는 비용이 생깁니다 (이 저장소의 규칙).

8. 함정

① Excel의 회계 서식

일반 서식 셀에 (1,234)를 입력하면 Excel이 -1234로 변환합니다. 1,234는 천 단위 구분자로 읽혀 1234가 됩니다. 정수 성분 2개를 적으려던 셀이 숫자 하나가 되는 자리입니다.

조용히 틀리지는 않습니다. 임포터는 숫자 셀을 "R" 포맷으로 문자열화하므로 파서에 도착하는 것은 -1234이고, 성분이 1개이므로 4.1의 개수 검사에 걸립니다. 합성 타입의 성분은 전부 2개 이상이라 이 경로는 항상 거부됩니다.

대응은 메시지입니다 — 성분이 1개이고 그것이 숫자 셀에서 왔으면, 개수만 보고하지 않고 컬럼 서식을 텍스트로 두거나 앞에 '를 붙이라고 지시합니다.

괄호를 필수로 두지 않는 것이 이 함정 때문입니다. 괄호가 없는 111, 222는 회계 서식으로 읽히지 않습니다.

#으로 시작하는 셀

수식 오류의 검출은 셀의 오류 코드로 하고 텍스트로 하지 않습니다 — SheetGridReaderExcelErrorCode를 보고 #REF!·#N/A로 렌더링합니다. #3366CC는 텍스트 셀이므로 OnFormulaError의 경로에 걸리지 않습니다.

③ 진법 리터럴의 순서

ParseValue는 타입별 분기보다 먼저 0x·0b를 10진수로 바꿉니다. 대상은 TakesRadixLiteral이 허용하는 숫자 4종뿐이므로, 색 2종을 그 목록에 넣지 않으면 0x3366CC가 색 파서에 원문 그대로 도착합니다. 넣지 않습니다 — 넣으면 6자리 색이 정수 3368140으로 먼저 바뀝니다.

성분 안쪽은 다릅니다. color32의 튜플 성분은 int이므로 (0xFF, 0x80, 0x40)이 성분마다 진법 리터럴 경로를 지납니다 — 4.1의 「성분의 표기는 그 성분 타입의 것」이 여기에 그대로 적용됩니다.

④ 배열 구분자와의 충돌

성분 구분자가 쉼표로 고정이므로, DefaultDelimiter가 쉼표인 소스 항목에서는 vec2i[]의 원소 경계와 성분 경계가 같은 문자가 됩니다. 지금은 T[]를 담지 않으므로 충돌이 없고, 담는 날의 선행 조건입니다.

quat의 길이

상태판정
길이 0오류 — 회전이 아닙니다
길이가 1에서 벗어남 (허용 오차 1e-4)경고

경고인 것은 시트에 손으로 적은 사원수가 반올림 때문에 조금 어긋나는 것이 정상이기 때문입니다. 빌드를 차단해야 하는 프로젝트는 이미 있는 TreatWarningsAsErrors로 차단합니다 — asset이 같은 자리에서 같은 처리를 합니다.

9. 담지 않는 것

  • 한 셀의 가변 배열 vec2f[]. 확장 결과가 「셀 하나에서 나온 가변 길이 레코드 배열」이고, 그것은 가변 길이 레코드 배열이 다루지 않는 새 형태입니다. 고정 개수는 Pos1·Pos2로 이미 됩니다(4.5).
  • double 성분 vec2d. 좌표를 배정밀도로 싣는 요구가 확인되면 그때 추가합니다 — 접미가 이미 성분 타입을 적고 있으므로 이름은 비어 있습니다.
  • rect · bounds · matrix. 성분 개수만 다른 것이 아니라 성분의 뜻이 규약을 요구합니다 (rect(x,y,w,h)인지 (x0,y0,x1,y1)인지).
  • 상수 세트의 합성 타입. ~~const:~~의 값은 한 칸의 값 하나이고 펼칠 컬럼이 없으므로, 타입이 13개 생성기까지 그대로 갑니다. 성분을 상수로 따로 선언합니다. 7절의 공용 타입이 생기면 다시 볼 자리입니다.
  • 리니어 · HDR 변환과 색 공간 선언. 4.3.
  • colorcolor32 사이의 자동 변환. 컬럼의 타입이 그 컬럼이 담는 것을 규정하고, 어느 쪽으로 담을지는 시트를 적는 사람의 판단입니다. 실수 튜플을 color32 컬럼에서 받아 255를 곱해 주는 편의를 두지 않는 이유가 4.3에 있습니다.
  • 합성 컬럼의 존재 비트. 4.5.
  • 성분별 컬럼 제약. min/max가 성분에 대한 것인지 크기에 대한 것인지 갈리므로, 합성 컬럼에 범위 제약이 붙으면 지금은 거부합니다.
  • 축 규약 선언과 그것이 열어 주는 up·forward. 5절.
  • Pantone · RAL 팔레트. 4.4.

10. 검증 게이트

게이트확인하는 것
레코드 동치 대조같은 데이터를 Pos: vec3fPos.X·Pos.Y·Pos.Z로 각각 내보내 바이트가 같은지. 접기가 실제로 일어났는지를 판정하는 게이트입니다 — 접히지 않았다면 어느 생성기가 타입을 렌더링하지 못하고 멈춥니다
표기 픽스처4절 표의 거부 목록 전부 — 성분 개수 불일치, 괄호 불균형, 빈 성분, 접두 불일치, 알 수 없는 색 이름, 영벡터 축, color32의 소수점, 0~255 밖의 성분
골든 픽스처합성 타입 5종을 든 테이블 하나. 3개 언어와 json·binary입니다 — 접힌 뒤의 형태는 모든 언어가 이미 내는 레코드이고, 여기에서 볼 것은 합성 컬럼이 그 레코드로 도착하는지입니다
색 2종 대조CSS 이름 148개와 # 3·4·6·8자리를 양쪽 타입에 넣어, color32는 8비트 값과 정확히 같고 color는 255로 되돌렸을 때 같은지. 팔레트를 8비트로 보관하는 결정(4.4)이 실제로 지켜졌는지가 여기에서 드러납니다
color32의 폭0~255 컬럼이 BITPACK 폭 8로 인코딩되는지. 정수 하나로 접지 않은 근거(4.3)가 성립하는지를 확인하는 자리입니다
Excel 서식(1,234)가 든 워크북이 오류를 내고, 그 메시지가 서식을 지목하는지
기존 골든 무변경합성 컬럼이 없는 시트의 산출물이 한 바이트도 움직이지 않는지. 확장이 실행되는 조건을 잘못 잡으면 여기가 먼저 드러납니다
합성 컬럼 뒤의 평범한 컬럼컬럼 하나가 넷이 되면 그 뒤의 모든 컬럼이 이동합니다. 픽스처의 마지막 컬럼이 그 자리에 있는 것은 장식이 아니라 이 게이트입니다 — 셀을 옮기기 전에 번호를 다시 매기면 여기가 어긋납니다
인덱스 키 거부vec2i 컬럼에 *를 붙였을 때 그 타입 이름과 함께 거부하는지
팔레트 부재없는 팔레트 접두와, 팔레트에 없는 이름을 구별해 보고하는지

11. 구현 — 순서와 결과

단계무엇상태
1타입 이름IsValidTypeName·ParseValueType·EmptyValueOf
2셀 파서 — 4.1·4.2·4.3. 순수 함수로 두고 표기 픽스처를 먼저됨. 이 타입의 내용은 받는 것보다 거부하는 것에 있습니다
3확장 — 6.1. 캐시 무효화와 태그 재할당됨. 레이아웃 파서 무변경
4팔레트 — 내장 css와 recipe의 Palettes
5진단 — 8절 ①의 서식 지목, 4.2의 접두 불일치, 6.1.1의 셋
6문서시트의 타입 표

레코드 동치 대조가 통과합니다. compositecomposite-expanded 두 픽스처가 같은 이름의 테이블을 두 표기로 적고, 산출된 Vectors.tcb바이트 동일합니다. 기존 골든 17개는 한 바이트도 움직이지 않습니다.

설계에서 달라진 것이 하나 있습니다. 이 문서는 확장을 레이아웃 파서의 AssignTags 앞에 두려고 했는데, 쿠커의 패스로 옮기면 레이아웃이 셋 다 무변경이 되고 새 레이아웃이 이 타입을 그냥 갖게 됩니다. 대가는 태그 재할당 한 가지이고, 서수 태그는 이름이 아니므로 잃는 것이 없습니다.

7절의 2·3단계는 별도 개정입니다. 1단계만으로 시트의 컬럼 수와 표기 문제는 해결되고, 남는 것은 소비 측의 타입 정체성입니다.