@hatiolab/figure-model 0.1.30 → 0.1.31
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -0
- package/dist/index.js.map +1 -1
- package/dist/release-contract.d.ts +2 -2
- package/dist/release-contract.d.ts.map +1 -1
- package/dist/release-contract.js +45 -3
- package/dist/release-contract.js.map +1 -1
- package/dist/types.d.ts +15 -4
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +15 -4
- package/dist/types.js.map +1 -1
- package/dist/v3-asset-types.d.ts +116 -0
- package/dist/v3-asset-types.d.ts.map +1 -0
- package/dist/v3-asset-types.js +2 -0
- package/dist/v3-asset-types.js.map +1 -0
- package/dist/v3-asset.d.ts +8 -0
- package/dist/v3-asset.d.ts.map +1 -0
- package/dist/v3-asset.js +135 -0
- package/dist/v3-asset.js.map +1 -0
- package/dist/v3-authoring-session.d.ts +119 -0
- package/dist/v3-authoring-session.d.ts.map +1 -0
- package/dist/v3-authoring-session.js +132 -0
- package/dist/v3-authoring-session.js.map +1 -0
- package/dist/v3-capabilities.d.ts +3 -0
- package/dist/v3-capabilities.d.ts.map +1 -0
- package/dist/v3-capabilities.js +221 -0
- package/dist/v3-capabilities.js.map +1 -0
- package/dist/v3-contract.d.ts +7 -0
- package/dist/v3-contract.d.ts.map +1 -0
- package/dist/v3-contract.js +12 -0
- package/dist/v3-contract.js.map +1 -0
- package/dist/v3-create.d.ts +25 -0
- package/dist/v3-create.d.ts.map +1 -0
- package/dist/v3-create.js +50 -0
- package/dist/v3-create.js.map +1 -0
- package/dist/v3-document.d.ts +5 -0
- package/dist/v3-document.d.ts.map +1 -0
- package/dist/v3-document.js +31 -0
- package/dist/v3-document.js.map +1 -0
- package/dist/v3-editor-workspace.d.ts +334 -0
- package/dist/v3-editor-workspace.d.ts.map +1 -0
- package/dist/v3-editor-workspace.js +130 -0
- package/dist/v3-editor-workspace.js.map +1 -0
- package/dist/v3-graph-types.d.ts +91 -0
- package/dist/v3-graph-types.d.ts.map +1 -0
- package/dist/v3-graph-types.js +2 -0
- package/dist/v3-graph-types.js.map +1 -0
- package/dist/v3-graph.d.ts +5 -0
- package/dist/v3-graph.d.ts.map +1 -0
- package/dist/v3-graph.js +631 -0
- package/dist/v3-graph.js.map +1 -0
- package/dist/v3-json.d.ts +13 -0
- package/dist/v3-json.d.ts.map +1 -0
- package/dist/v3-json.js +94 -0
- package/dist/v3-json.js.map +1 -0
- package/dist/v3-part-edit.d.ts +12 -0
- package/dist/v3-part-edit.d.ts.map +1 -0
- package/dist/v3-part-edit.js +53 -0
- package/dist/v3-part-edit.js.map +1 -0
- package/docs/assembly-constraints-v3.md +141 -0
- package/docs/prototypes/README.md +73 -0
- package/docs/prototypes/render-dryroom.py +60 -0
- package/docs/prototypes/render-full-dryroom.mjs +86 -0
- package/docs/prototypes/shapeassembly-probe-results.json +325 -0
- package/docs/prototypes/shapeassembly-probe.py +84 -0
- package/docs/prototypes/v3-asset-samples.mjs +15 -0
- package/docs/prototypes/v3-asset-store.mjs +52 -0
- package/docs/prototypes/v3-asset-store.test.mjs +59 -0
- package/docs/prototypes/v3-asset.mjs +1 -0
- package/docs/prototypes/v3-asset.schema.json +44 -0
- package/docs/prototypes/v3-asset.test.mjs +68 -0
- package/docs/prototypes/v3-authoring-session.mjs +1 -0
- package/docs/prototypes/v3-authoring-session.test.mjs +65 -0
- package/docs/prototypes/v3-capability-plan.mjs +1 -0
- package/docs/prototypes/v3-capability-plan.test.mjs +56 -0
- package/docs/prototypes/v3-capability-samples.mjs +23 -0
- package/docs/prototypes/v3-document.mjs +2 -0
- package/docs/prototypes/v3-document.schema.json +66 -0
- package/docs/prototypes/v3-document.test.mjs +55 -0
- package/docs/prototypes/v3-dryroom-mesh.mjs +60 -0
- package/docs/prototypes/v3-dryroom-mesh.test.mjs +30 -0
- package/docs/prototypes/v3-editor-browser.mjs +97 -0
- package/docs/prototypes/v3-editor-workspace.mjs +1 -0
- package/docs/prototypes/v3-editor-workspace.test.mjs +35 -0
- package/docs/prototypes/v3-feature-pattern.test.mjs +131 -0
- package/docs/prototypes/v3-full-conveyor.mjs +60 -0
- package/docs/prototypes/v3-full-conveyor.test.mjs +61 -0
- package/docs/prototypes/v3-full-dryroom.mjs +67 -0
- package/docs/prototypes/v3-full-dryroom.test.mjs +54 -0
- package/docs/prototypes/v3-full-forklift.mjs +40 -0
- package/docs/prototypes/v3-full-forklift.test.mjs +37 -0
- package/docs/prototypes/v3-full-robot.mjs +35 -0
- package/docs/prototypes/v3-full-robot.test.mjs +68 -0
- package/docs/prototypes/v3-kernel.mjs +147 -0
- package/docs/prototypes/v3-kernel.test.mjs +144 -0
- package/docs/prototypes/v3-layout.test.mjs +281 -0
- package/docs/prototypes/v3-linear-comparison.py +183 -0
- package/docs/prototypes/v3-more-samples.test.mjs +182 -0
- package/docs/prototypes/v3-payload-collision.mjs +54 -0
- package/docs/prototypes/v3-payload-collision.test.mjs +68 -0
- package/docs/prototypes/v3-payload-fit.mjs +58 -0
- package/docs/prototypes/v3-payload-fit.test.mjs +59 -0
- package/docs/prototypes/v3-repeated-binding.mjs +13 -0
- package/docs/prototypes/v3-repeated-binding.test.mjs +46 -0
- package/docs/prototypes/v3-runtime-browser.mjs +76 -0
- package/docs/prototypes/v3-samples.test.mjs +144 -0
- package/docs/prototypes/v3-semantics.test.mjs +55 -0
- package/docs/prototypes/v3-spatial-plan.test.mjs +102 -0
- package/docs/prototypes/v3-typed-plan.mjs +3 -0
- package/docs/prototypes/v3-typed-plan.test.mjs +70 -0
- package/docs/prototypes/v3-typed-repeat.test.mjs +96 -0
- package/docs/v3-asset-persistence.md +66 -0
- package/docs/v3-authoring-transactions.md +57 -0
- package/docs/v3-capability-bindings.md +109 -0
- package/docs/v3-common-kernel-experiment.md +116 -0
- package/docs/v3-core-semantics.md +303 -0
- package/docs/v3-cutover.md +27 -0
- package/docs/v3-design.md +388 -0
- package/docs/v3-document-contract.md +55 -0
- package/docs/v3-dryroom-profile-validation.md +87 -0
- package/docs/v3-editor-integration.md +59 -0
- package/docs/v3-full-conveyor-validation.md +69 -0
- package/docs/v3-full-dryroom-validation.md +55 -0
- package/docs/v3-full-forklift-validation.md +41 -0
- package/docs/v3-full-robot-validation.md +64 -0
- package/docs/v3-layout-system.md +318 -0
- package/docs/v3-minimal-model.md +255 -0
- package/docs/v3-operator-contracts.md +148 -0
- package/docs/v3-payload-collision-validation.md +42 -0
- package/docs/v3-payload-contact-validation.md +56 -0
- package/docs/v3-repeated-binding-validation.md +42 -0
- package/docs/v3-research-review.md +160 -0
- package/docs/v3-runtime-extraction.md +107 -0
- package/docs/v3-sample-validation-expanded.md +106 -0
- package/docs/v3-sample-validation.md +97 -0
- package/docs/v3-shapeassembly-reproduction.md +99 -0
- package/docs/v3-spatial-contracts.md +84 -0
- package/docs/v3-status.md +41 -0
- package/docs/v3-storage-integration.md +58 -0
- package/docs/v3-typed-repeat-contracts.md +79 -0
- package/package.json +1 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# V3 전체 컨베이어 검증 — 2026-09-21
|
|
2
|
+
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
|
+
|
|
5
|
+
## 판정과 범위
|
|
6
|
+
|
|
7
|
+
저장소 CONVEYOR seed의 **17개 파트 유형 전체**를 실험 V3 그래프로 작성했다. 기본 형상과 재질을 재현하면서 기존 반복 배치의 겹침을 의도적으로 제거했다. 제품 모델러 통합·애니메이션 재생·AI 저작 검증은 아직 아니다.
|
|
8
|
+
|
|
9
|
+
- 선언 및 메시 어댑터: [v3-full-conveyor.mjs](prototypes/v3-full-conveyor.mjs)
|
|
10
|
+
- 회귀 검사: [v3-full-conveyor.test.mjs](prototypes/v3-full-conveyor.test.mjs)
|
|
11
|
+
- 브라우저: `node docs/prototypes/render-full-dryroom.mjs --conveyor`
|
|
12
|
+
- 전체 테스트: `node --test docs/prototypes/v3-*.test.mjs`
|
|
13
|
+
|
|
14
|
+
## V2와 의도적으로 달라진 점
|
|
15
|
+
|
|
16
|
+
기본 길이 2,400mm에서 V2 반복 공식은 일반 롤러 16개를 중심 간격 150mm로 생성한다. 양 끝 일반 롤러 중심은 ±1,125mm이며, 별도의 굵은 끝 롤러 중심은 ±1,140mm다.
|
|
17
|
+
|
|
18
|
+
일반 롤러 반지름 48mm, 끝 롤러 반지름 75mm이고 중심 거리는 15mm이므로, `15 + 48 < 75`다. 일반 롤러 길이 520mm도 끝 롤러 길이 560mm보다 작다. 즉 **일반 롤러 두 개가 끝 롤러 내부에 완전히 묻힌다.** 축 방향 회전으로 이 문제는 해결되지 않는다.
|
|
19
|
+
|
|
20
|
+
V3는 양쪽 끝 공간을 먼저 확보한다.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
끝 여백 = 끝 롤러 중심의 가장자리 거리 60 + 반지름 75 + 최소 간격 10 = 145mm
|
|
24
|
+
n = 1 + floor((length - 2×145 - 96) / 150)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
이 모델의 허용 길이 범위 900..6000mm에서 사용 가능한 개수는 항상 양수다. 일반 연산자의 빈 배치 처리는 별도 반복 계약에 정의되어 있다. 배치는 남은 공간 가운데 정렬한다. 기본 상태는 14개, 중심 범위 ±975mm이며 끝 롤러와 표면 간격은 42mm다. 10mm는 실험 모델의 명시적인 저작 의도이지 모든 컨베이어의 산업 표준 값이 아니다.
|
|
28
|
+
|
|
29
|
+
## 편집 의도와 관계
|
|
30
|
+
|
|
31
|
+
| 입력 | 변경되는 것 | 유지되는 것 |
|
|
32
|
+
|---|---|---|
|
|
33
|
+
| length | 프레임·가드·데크 길이, 끝 부품·다리 위치, 일반 롤러 개수 | 롤러 반지름·간격, 끝 부품 크기 |
|
|
34
|
+
| width | 롤러 축 길이, 프레임·다리 횡방향 위치, 발판 길이 | 부재 단면, 좌우 접합 관계 |
|
|
35
|
+
| rollerHeight | 상부 조립 높이, 다리 길이 | 발판 위치와 다리 하단 접촉 |
|
|
36
|
+
| angle (state) | 일반 롤러의 로컬 축 회전 | 개수·중심·축 방향, 다른 부품 |
|
|
37
|
+
|
|
38
|
+
원본 run 채널의 일반 롤러 회전 의도를 보존한다. 프로토타입은 angle을 직접 받는다. 원본의 0.833초 주기 키프레임 재생기·보간·시간 바인딩을 구현한 것은 아니다. 끝 롤러는 원본에서도 해당 채널의 target이 아니므로 이번에는 회전시키지 않는다.
|
|
39
|
+
|
|
40
|
+
## 검증 결과
|
|
41
|
+
|
|
42
|
+
- 17개 파트 유형을 빠짐없이 포함. 반복하지 않는 16개 파트의 정점 집합 편차 **0mm**.
|
|
43
|
+
- 일반 롤러 역시 위치 이동을 제거하고 비교하면 원본 정점 집합과 일치. 원본 segments 12/16 및 재질 선언 유지.
|
|
44
|
+
- 길이 3 × 폭 3 × 높이 3 × 회전 5 = **135개 전체 상태**.
|
|
45
|
+
- 실제 삼각형 메시 **4,680개**의 닫힘, 방향성 체적, 퇴화 삼각형 검사 통과.
|
|
46
|
+
- 발판–다리–프레임 접촉, 반복 간격, 양쪽 끝 여유 공간, 회전 축 방향 검사 통과.
|
|
47
|
+
- 개수 변경 경계 985.999 / 986 / 986.001mm, ID 유지, 입력 오류 후 정상 평가 복구 검사 통과.
|
|
48
|
+
|
|
49
|
+
Chrome WebGL에서 직접 이미지를 확인했다. 환경 반사광을 포함한 동일 실험 조명·카메라에서:
|
|
50
|
+
|
|
51
|
+
| 상태 | draw calls | 삼각형 |
|
|
52
|
+
|---|---:|---:|
|
|
53
|
+
| 원본 재구현 | 32 | 1,612 |
|
|
54
|
+
| V3 기본 | 30 | 1,516 |
|
|
55
|
+
| V3 회전 37° | 30 | 1,516 |
|
|
56
|
+
| V3 길이3000·폭900·높이700·회전37° | 34 | 1,708 |
|
|
57
|
+
|
|
58
|
+
원본과 V3 기본 상태의 해당 시점 RGBA 채널 차이는 0이었다. **메시가 같다는 뜻은 아니다.** 원본의 불필요한 두 롤러가 완전히 가려져 영상에는 나타나지 않기 때문이다. 영상만으로 내부 중첩을 판정할 수 없다는 사례다. 브라우저 pageerror는 없었다. 임시 이미지: `/private/tmp/figure-v3-full-conveyor.png`.
|
|
59
|
+
|
|
60
|
+
## 남은 한계
|
|
61
|
+
|
|
62
|
+
1. 원본 비교는 제품 생성 코드를 읽고 만든 어댑터 기준이다. 제품 렌더러 직접 실행이 아니며 rounded profile 함수도 공유한다.
|
|
63
|
+
2. 재질·분할 수는 seed 메타데이터를 붙인다. V3 전체 직렬화/재질/품질 정책 계약의 완성을 뜻하지 않는다.
|
|
64
|
+
3. 접촉 관계는 치수 의존 그래프로 표현했다. 사용자가 접합면을 선택하는 UI 및 feature 기반 저작 작업으로의 연결은 별도 검증이 필요하다.
|
|
65
|
+
4. 검사한 접합과 끝 롤러 간격 외의 모든 부품 간 충돌을 증명한 것은 아니다. 받침 하단은 원본처럼 y=6mm이며 바닥 접촉으로 몰래 변경하지 않았다.
|
|
66
|
+
5. 반복 ID는 순번 기반이다. 크기 변경 시 ID는 유지되지만 가운데 정렬 때문에 위치는 움직인다. 삭제 후 재생성·외부 참조의 제품 정책은 여전히 별도 계약이 필요하다.
|
|
67
|
+
6. 개별 메시 렌더링 수치다. 제품의 배칭/인스턴싱, 프레임 시간이나 대규모 장면 성능을 보장하지 않는다.
|
|
68
|
+
|
|
69
|
+
전체 샘플 검증의 현재 범위는 드라이룸과 컨베이어다. 로봇암·포크리프트의 모든 부품·재질·동작을 포함한 동일 수준 검증과 실제 저작 UX 검증은 남아 있다.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# V3 전체 DRY_ROOM 검증 — 2026-09-21
|
|
2
|
+
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
|
+
|
|
5
|
+
## 판정
|
|
6
|
+
|
|
7
|
+
저장소 기본 DRY_ROOM의 **6개 파트 전체**를 실험 V3 그래프로 작성하고, 기준 형상 재현과 편집 관계 및 격리된 Chrome WebGL 렌더링을 검증했다. 대표 모델 전체의 제품 가치 검증은 아직 완료가 아니다. 실제 모델러 UI, 서버의 수정된 드라이룸, 다른 대표 모델 전체의 검증을 포함하지 않는다.
|
|
8
|
+
|
|
9
|
+
## 범위와 재현 방법
|
|
10
|
+
|
|
11
|
+
- 원본: `operato-application/packages/operato-figure/server/seed/figure-samples.json`의 DRY_ROOM.
|
|
12
|
+
- 전체 선언: [v3-full-dryroom.mjs](prototypes/v3-full-dryroom.mjs).
|
|
13
|
+
- 테스트: [v3-full-dryroom.test.mjs](prototypes/v3-full-dryroom.test.mjs).
|
|
14
|
+
- 브라우저 실험: [render-full-dryroom.mjs](prototypes/render-full-dryroom.mjs).
|
|
15
|
+
- 실행: `node --test docs/prototypes/v3-*.test.mjs`, `node docs/prototypes/render-full-dryroom.mjs`.
|
|
16
|
+
|
|
17
|
+
브라우저 스크립트는 이 개발 환경의 설치된 Three.js·Playwright·Chrome을 사용한다. 별도 임시 loopback 서버를 열고 종료하며 제품 서버·DB·자산·의존성 설정을 변경하지 않는다. 경로는 개발 환경에 종속되어 있다.
|
|
18
|
+
|
|
19
|
+
## 결과
|
|
20
|
+
|
|
21
|
+
| 파트 | 삼각형 | 기본 상태 원본 대비 정점 집합 최대 편차 |
|
|
22
|
+
|---|---:|---:|
|
|
23
|
+
| shell | 12 | 0mm |
|
|
24
|
+
| portal-in | 28 | 0mm |
|
|
25
|
+
| portal-out | 28 | 0mm |
|
|
26
|
+
| lamp-in | 64 | 0mm |
|
|
27
|
+
| lamp-out | 64 | 0mm |
|
|
28
|
+
| readout | 140 | 0mm |
|
|
29
|
+
|
|
30
|
+
재질 선언도 원본과 일치한다. 비교 기준 메시 생성기는 제품의 형상 생성 코드를 읽고 재구현한 것으로, 제품 렌더러를 직접 실행한 결과는 아니다. 특히 rounded profile 함수는 두 경로가 공유하므로 독립적인 오라클로 볼 수 없다.
|
|
31
|
+
|
|
32
|
+
- 27개 치수 조합 × 하단 2개 값 × 램프 높이 3개 값 = **162개 전체 모델**, 메시 **972개** 검사 통과.
|
|
33
|
+
- 원본 불변성, 유효하지 않은 입력 후 재평가, 관계 유지 검사 통과.
|
|
34
|
+
- 전체 프로토타입 회귀 테스트 **80/80 통과**.
|
|
35
|
+
- Chrome WebGL 동일 카메라 기준 원본 재구현과 V3 기본 상태의 RGBA 채널 차이 **0**.
|
|
36
|
+
- 원본·V3 기본·하단 제거·크기 및 램프 위치 변경의 네 상태 모두 **6 draw calls / 336 triangles**. 브라우저 pageerror 없음.
|
|
37
|
+
- 생성 이미지: `/private/tmp/figure-v3-full-dryroom.png` (임시 산출물).
|
|
38
|
+
|
|
39
|
+
동일 영상은 해당 카메라에서만 비교했다. 보이지 않는 후면은 정점·관계 검사로 확인했으며, 후면 영상 비교나 실제 제품 전체 렌더링 검증을 대체하지 않는다.
|
|
40
|
+
|
|
41
|
+
## 편집 의미
|
|
42
|
+
|
|
43
|
+
하단 제거는 portal의 프로파일 하단을 -60mm에서 0mm로 바꾼다. 전체 bounding box를 축소하지 않는다. 상단·개구부 상단과 램프 위치는 이 편집으로 이동하지 않는다. 폭·높이·깊이 변경과 램프 높이 변경은 별도 입력이다.
|
|
44
|
+
|
|
45
|
+
readout의 접속 offset을 잘못 지정해 원본보다 50mm 앞에 배치한 오류를 전체 정점 비교에서 발견하고 수정했다. 이는 작은 부분 테스트만으로 전체 재현 성공을 주장해서는 안 되는 사례다.
|
|
46
|
+
|
|
47
|
+
## 제품 가치 판단의 한계와 다음 게이트
|
|
48
|
+
|
|
49
|
+
1. **원본 자체의 품질:** shell은 현재 seed와 제품 wall 구현상 속이 막힌 상자다. 입구 안이 벽으로 보이는 것도 그대로 재현했다. 중공 공간·벽 두께·실제 출입문 동작을 검증한 것이 아니다. 이 seed에는 gate 애니메이션도 없다.
|
|
50
|
+
2. **선언 완결성:** 이 초기 렌더링 검증은 seed 재질을 사용했다. 후속 자산 계약에서는 재질·팔레트를 JSON으로 저장·복원한다. 전체 표현 범위의 완결성을 주장하는 것은 아니다.
|
|
51
|
+
3. **사용성:** 후속 공통 workspace에서 UI/AI 입력 편집과 격리 UI 흐름을 검증했다. 실제 제품 모델러·AI-dock 연결은 남아 있다.
|
|
52
|
+
4. **성능:** 6개 독립 메시의 실험 수치다. 제품의 병합·인스턴싱·LOD, 대규모 배치 성능 또는 GPU 프레임 시간 보장이 아니다.
|
|
53
|
+
5. **다른 대표 모델:** 로봇암·컨베이어·포크리프트의 전체 모델 실험과 자산 저장·복원 검증도 후속 단계에서 수행했다. 각 모델의 알려진 형상 문제와 미검증 범위는 개별 검증 문서에 남긴다. 실제 사용자 자산 전체의 전환 완료를 뜻하지 않는다.
|
|
54
|
+
|
|
55
|
+
결론: 전체 모델을 대상으로 한 첫 검증 게이트는 통과했다. 이상적인 모델 명세와 제품 가치를 입증하려면 원본 재현 외에도 의도적인 개선 모델과 실제 저작 UX 검증이 필요하다.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# V3 전체 포크리프트 검증 — 2026-09-21
|
|
2
|
+
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
|
+
|
|
5
|
+
## 판정
|
|
6
|
+
|
|
7
|
+
저장소 FORKLIFT seed의 **20개 파트 전체**와 lift/reach/drive를 실험 V3 그래프로 작성했다. 기본 형상 재현과 동시 상태 갱신 검증을 통과했다. 실제 제품 모델러·시간 재생기·적재 기능·충돌/안전성까지 완료한 것은 아니다.
|
|
8
|
+
|
|
9
|
+
- [전체 선언](prototypes/v3-full-forklift.mjs)
|
|
10
|
+
- [테스트](prototypes/v3-full-forklift.test.mjs)
|
|
11
|
+
- 실행: `node --test docs/prototypes/v3-*.test.mjs`
|
|
12
|
+
- 브라우저: `node docs/prototypes/render-full-dryroom.mjs --forklift`
|
|
13
|
+
|
|
14
|
+
## 관계
|
|
15
|
+
|
|
16
|
+
내밈 프레임 → stage 프레임(상승 절반) → carriage 프레임(나머지 절반)으로 합성한다. 포크와 carriage는 최종 프레임을 공유하며 상승/내밈이 두 번 적용되지 않는다. mast는 내밈만, stage는 상승 절반과 내밈을 따른다.
|
|
17
|
+
|
|
18
|
+
forkLength는 설계 입력이며 포크 뒤쪽 z=360mm를 유지하고 앞쪽만 바꾼다. 좌우/상하 4개 포크는 같은 길이를 공유한다. 나머지 차량 치수 전체를 파라미터화한 것은 아니다.
|
|
19
|
+
|
|
20
|
+
주 구동 휠의 회전은 원본 Rz(90°) 배치 후 로컬 Y 회전을 합성한다. 단순히 Euler Y에 더하는 방법을 쓰지 않아 축 방향이 고정된다. load-wheel에는 원본 drive 채널이 없어 자동 회전을 추가하지 않았다. 실제 바퀴 주행 거리와 회전의 물리적 연동은 검증 범위 밖이다.
|
|
21
|
+
|
|
22
|
+
## 결과
|
|
23
|
+
|
|
24
|
+
- 기본 상태 20개 파트 모두 정점 집합 최대 편차 **0mm**, 재질 선언 일치.
|
|
25
|
+
- 포크 길이3 × 상승5 × 내밈3 × 구동각5 = **225개 전체 상태**.
|
|
26
|
+
- 예상 위치는 구현의 그룹 분류가 아니라 원본 parameter 채널의 endpoint를 읽어 독립 계산했다. 모든 파트 일치.
|
|
27
|
+
- 메시 **4,500개** 닫힘·양의 체적·비퇴화 검사 통과.
|
|
28
|
+
- 포크 뒤쪽 장착 좌표, 상하 포크 간격400mm, carriage와 포크 상대 높이218mm 유지.
|
|
29
|
+
- 주 휠 축 방향·반지름에 따른 바닥 높이 유지, 잘못된 입력 거부, 오류 후 복구, 노드 순서 독립성 확인.
|
|
30
|
+
|
|
31
|
+
Chrome에서 원본·V3 기본·상승1000/내밈200·상승2000/내밈400/포크1275mm 이미지를 직접 확인했다. 각 상태 **20 draw calls / 1,032 triangles**, pageerror 없음. 원본 재구현과 V3 기본의 동일 카메라 픽셀 채널 차이는 0이었다. 이미지: `/private/tmp/figure-v3-full-forklift.png`.
|
|
32
|
+
|
|
33
|
+
## 한계
|
|
34
|
+
|
|
35
|
+
원본 형상 생성은 제품 코드를 참고한 재구현이다. rounded profile helper를 공유하며 독립적인 제품 렌더러 통합 테스트는 아니다. 시간 보간/clip 재생은 연결하지 않고 상태값을 직접 입력했다.
|
|
36
|
+
|
|
37
|
+
닫힌 개별 메시와 올바른 pose는 전체 조립의 무충돌을 증명하지 않는다. 원본 mast와 stage는 실선체 상자로 표현되어 정지 상태부터 내부가 겹친다. 텔레스코픽 기구의 실제 중공 단면을 재현한 것이 아니다. 경고등/라이다 등의 원본 배치도 미적·물리적 품질 검증을 별도로 받아야 한다.
|
|
38
|
+
|
|
39
|
+
적재 binding은 원본에 없으며 추가 구현한 것으로 계산하지 않는다. [capability binding 계약](v3-capability-bindings.md)은 물리 형상과 적재/파지 위치를 분리할 설계 초안이다.
|
|
40
|
+
|
|
41
|
+
이로써 드라이룸·컨베이어·로봇암·포크리프트 네 대표 모델의 전체 파트 실험은 존재한다. **제품 가치 검증 완료**를 의미하지 않는다. 발견한 원본 품질 문제, capability 구현, V3 직렬화/런타임, 실제 UI와 AI 편집 검증이 남아 있다.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# V3 전체 로봇암 검증 — 2026-09-21
|
|
2
|
+
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
|
+
|
|
5
|
+
## 판정
|
|
6
|
+
|
|
7
|
+
`src/fixtures/robot-arm-6dof.json`의 **10개 파트 전체, 6축 관절, 그리퍼**를 동일한 typed graph에 작성했다. 링크 길이와 관절 위치가 실제 형상 feature를 통해 함께 갱신되는 것을 확인했다. 기구학 검증은 통과했지만, 충돌 없는 제품 모델로 판정하지 않는다. 원본 그리퍼와 tool-seat의 간섭을 발견했기 때문이다.
|
|
8
|
+
|
|
9
|
+
## 구현과 재현
|
|
10
|
+
|
|
11
|
+
- [전체 선언 및 어댑터](prototypes/v3-full-robot.mjs)
|
|
12
|
+
- [검증 테스트](prototypes/v3-full-robot.test.mjs)
|
|
13
|
+
- `node --test docs/prototypes/v3-*.test.mjs`
|
|
14
|
+
- `node docs/prototypes/render-full-dryroom.mjs --robot`
|
|
15
|
+
|
|
16
|
+
베이스·어깨·상완·전완·손목2개·플랜지·손가락2개·tool-seat를 모두 포함한다. 원본에 있는 재질과 tool-seat capability 메타데이터를 보존한다. tool-seat에는 원본 재질이 없어 실험 어댑터에서 palette.neutral을 명시했다. 이는 제품의 기본 재질까지 동일하다는 주장이 아니다. cylinder의 기본 분할 수는 제품 코드에서 확인한 8을 사용했다.
|
|
17
|
+
|
|
18
|
+
## 관계 모델
|
|
19
|
+
|
|
20
|
+
각 링크는 자신의 형상에서 start/end 또는 bottom/top feature를 얻는다. 자식의 pose는 다음 관계로 결정한다.
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
자식 pose = 부모 끝면 world pose × 관절 회전/간격 × inverse(자식 시작면 local pose)
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
관절 원점을 별도 고정 좌표로 복제하지 않는다. 상완과 전완 길이를 각각 변경하면 끝면이 바뀌고 자식 전체가 따라간다. 단면과 손목 크기는 유지한다. 회전은 상태 입력이며 링크 길이는 설계 입력이다. 별도 로봇 전용 solver를 추가하지 않았다.
|
|
27
|
+
|
|
28
|
+
그리퍼는 플랜지 좌표계에서 왼쪽 `-35 + 20g`, 오른쪽 `35 - 20g`mm이며 g는 0..1이다. 플랜지가 회전한 후에도 로컬 스트로크 방향을 유지한다. 원본 7개 parameter의 값을 입력으로 표현했지만, clip duration/시간 보간 및 제품 플레이어를 연결한 것은 아니다. continuous joint의 실험 입력 범위는 원본 parameter의 ±360°이며 무한 누적 회전 지원을 증명하지 않는다.
|
|
29
|
+
|
|
30
|
+
## 결과
|
|
31
|
+
|
|
32
|
+
- 기본 상태 10개 파트 모두 원본 재구현 대비 정점 집합 편차 **0mm**.
|
|
33
|
+
- 상완 길이 3 × 전완 길이 3 × 동시 6축 상태 32 × 그리퍼 3 = **864개 전체 상태**.
|
|
34
|
+
- 컴파일러와 별개로 Three.js 행렬 연산으로 작성한 순기구학 기준과 모든 파트의 위치·회전 일치.
|
|
35
|
+
- 실제 형상 feature 기반 관절 연결 위치 **5,184회** 일치.
|
|
36
|
+
- 생성 메시 **8,640개** 닫힘·양의 방향성 체적·비퇴화 검사 통과.
|
|
37
|
+
- 관절 범위 초과와 잘못된 링크 길이 거부, 오류 이후 복구, 노드 선언 순서 독립성 검사 통과.
|
|
38
|
+
- 전체 프로토타입 회귀 테스트 **88/88 통과**. 이 숫자에는 아래 알려진 결함을 탐지하는 테스트도 포함하므로 제품 합격률이 아니다.
|
|
39
|
+
|
|
40
|
+
Chrome WebGL에서 기본 상태·6축과 그리퍼 동시 변경·링크 길이 변경 이미지를 직접 확인했다. 네 패널 모두 **10 draw calls / 220 triangles**, pageerror 없음. 원본 재구현과 V3 기본 상태의 해당 카메라 RGBA 채널 차이는 0이다. 임시 이미지: `/private/tmp/figure-v3-full-robot.png`.
|
|
41
|
+
|
|
42
|
+
원본 렌더러를 직접 구동한 것이 아니라 형상 생성 경로를 재구현했다. 독립 FK도 같은 직렬 체인이라는 전제를 공유한다. 이미지 한 시점의 일치는 전체 동작·충돌·물리적 타당성 보장이 아니다.
|
|
43
|
+
|
|
44
|
+
## 발견한 원본 결함: tool-seat와 손가락 간섭
|
|
45
|
+
|
|
46
|
+
tool-seat는 폭40 × 높이20 × 깊이40mm의 실제 cube로 선언되어 있고 플랜지 위에 놓인다. 손가락은 폭12mm이며 y=1250..1310에 걸친다. tool-seat의 y=1250..1270과 겹친다.
|
|
47
|
+
|
|
48
|
+
손가락 안쪽 간격은 `58 - 40g`mm다. g>0.45부터 40mm seat와 양쪽 손가락이 겹친다. 완전 닫힘에서는 각 손가락의 교집합이 `11 × 20 × 24 = 5,280mm³`다. 공통 플랜지 좌표계에서 계산하므로 다른 관절의 회전에 무관하다.
|
|
49
|
+
|
|
50
|
+
이것을 숨기거나 gripper 범위를 자동으로 줄이지 않았다. 다음 설계 판단이 필요하다.
|
|
51
|
+
|
|
52
|
+
1. tool-seat가 **실제 부품**이면 유효한 치수·위치·스트로크 관계를 다시 저작해야 한다.
|
|
53
|
+
2. 단지 **적재/파지 위치 또는 영역**이면 렌더링할 solid 부품 없이도 capability를 feature/frame과 영역에 바인딩할 수 있어야 한다.
|
|
54
|
+
3. 어느 경우에도 의미상 영역과 충돌 검사 대상 solid를 암묵적으로 혼용하면 안 된다. 원본의 의도를 확인하지 않고 capability 상자를 자동으로 숨기는 것도 정답이 아니다.
|
|
55
|
+
|
|
56
|
+
이는 핵심 변환 알고리즘 실패가 아니라, capability 부가 계약과 물리 형상을 분리해 정의해야 한다는 검증 근거다. 현재 코드는 원본을 보존한 상태이며 이 결함의 제품 수정은 완료되지 않았다.
|
|
57
|
+
|
|
58
|
+
## 남은 제품 검증
|
|
59
|
+
|
|
60
|
+
- 자기충돌 및 작업 공간 전체 충돌, 관절 하우징의 시각적 연결 품질.
|
|
61
|
+
- IK, 물리적 로봇 안전성·동역학은 이번 범위 밖이다.
|
|
62
|
+
- capability 동작, 시간 기반 애니메이션, UI/AI의 의미 있는 관절명·그리퍼 편집.
|
|
63
|
+
- 재질·capability를 포함하는 V3 완전 직렬화와 제품 런타임 연결.
|
|
64
|
+
- 포크리프트 전체 모델 검증.
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# Figure v3: 계층형 3차원 레이아웃 시스템
|
|
2
|
+
|
|
3
|
+
> 현재 구현·검증·제품 연결 상태는 [V3 통합 현황](v3-status.md)을 따른다. 본문의 단계별 연구/검증 기록은 제품 전체 완료 선언이 아니다.
|
|
4
|
+
|
|
5
|
+
> 상태 변경: Flex/Grid 도입을 전제한 **r1 비교안**으로 보존한다. 구현 기준으로 확정하지 않는다.
|
|
6
|
+
> 자동 크기 측정과 Grid 다중 span 배분에 확인된 반례가 있다.
|
|
7
|
+
> 현재 검토 방향은 [최소 실행 모델 r2](v3-minimal-model.md)이며, Flex/Grid는 필수 요구가 아니다.
|
|
8
|
+
|
|
9
|
+
2026-09-20 · 설계 기준안 r1. **제품에 구현/배포된 기능이 아니다.**
|
|
10
|
+
좌표·부착·운동의 하위 수학 계약은 [v3-design.md](v3-design.md).
|
|
11
|
+
이 문서가 컨테이너, 크기 배분, 순환 의존, overflow, 증명 범위를 우선 정의한다.
|
|
12
|
+
CSS 호환 구현을 목표로 하지 않는다. Flex/Grid의 공간 배분 개념을 Figure에 적용한다.
|
|
13
|
+
|
|
14
|
+
## 1. 핵심 결정
|
|
15
|
+
|
|
16
|
+
모델을 “좌표가 나열된 부품”이 아니라 **공간을 분할하고 그 공간 안에 형상을 배치하는 프로그램**으로 정의한다.
|
|
17
|
+
|
|
18
|
+
- 컨테이너는 논리적 공간이며 mesh, 재질, draw call을 만들지 않는다.
|
|
19
|
+
- layout box(배치 공간), geometry(실제 표면), motion frame(운동 좌표계)은 구별한다.
|
|
20
|
+
- 한 부품의 크기를 두 시스템이 덮어쓰지 않는다. 컨테이너는 slot을 배분하고,
|
|
21
|
+
부품의 fit 정책은 그 slot에서 실제 형상 크기와 정지 위치를 결정한다.
|
|
22
|
+
- 크기 유지, 균등 분배, 틈 유지, 맞춤은 공통 연산이다. 문짝/램프별 예외 코드는 없다.
|
|
23
|
+
- AI와 UI는 같은 선언을 편집한다. 사용자가 분할 수, anchor 식, 솔버 우선순위를
|
|
24
|
+
알아야만 모델을 만들 수 있는 구조는 목표가 아니다.
|
|
25
|
+
- 임의 제약의 최적해를 추측하는 CAD solver 대신, 종료와 결정성이 명확한 제한된 언어로 시작한다.
|
|
26
|
+
|
|
27
|
+
## 2. 노드·좌표·소유권
|
|
28
|
+
|
|
29
|
+
논리 트리는 node id가 불변인 단일 부모 트리다. 루트 치수는 외부에서 주는 유한한 양수 mm다.
|
|
30
|
+
각 node는 중심 원점, 오른손 좌표, Y 상향, 양의 extent를 가진다.
|
|
31
|
+
루트의 중심 frame은 Figure 바닥 원점에서 (0, height/2, 0)만큼 위다.
|
|
32
|
+
자식의 배치는 부모 content box의 local 좌표에서 계산한다.
|
|
33
|
+
|
|
34
|
+
컨테이너 padding은 축마다 minus/plus 두 값이다. 모든 padding/gap은 유한한 0 이상 길이다.
|
|
35
|
+
content 크기 C = outerSize - paddingMinus - paddingPlus.
|
|
36
|
+
content 중심 offset = (paddingMinus - paddingPlus)/2.
|
|
37
|
+
C가 음수면 진단한다. 0인 논리 공간은 허용하지만 그 안의 양수 형상은 들어갈 수 없다.
|
|
38
|
+
|
|
39
|
+
| 구조 | 소유하는 값 |
|
|
40
|
+
| --- | --- |
|
|
41
|
+
| container layout | 자식 slot의 크기·중심·정지 방향 |
|
|
42
|
+
| item fit | slot 안에서의 geometry 크기·offset |
|
|
43
|
+
| geometry provider | local 표면·bounds·안정된 feature |
|
|
44
|
+
| motion forest | 정지 배치 이후의 강체 움직임 |
|
|
45
|
+
| author grouping | 선택·이름·재사용; 계산 자유도 없음 |
|
|
46
|
+
|
|
47
|
+
컨테이너의 flow 자식은 local 축 정렬을 기본으로 한다. 컨테이너 전체는 상수 회전할 수 있다.
|
|
48
|
+
개별 자식의 임의 회전은 wrapper slot 안의 fit 단계로 분리한다.
|
|
49
|
+
flow 위치와 수동 position을 동시에 쓰는 것은 금지한다. 직접 위치를 지정하려면
|
|
50
|
+
해당 자식을 explicitly placed로 바꾸며 flow의 공간 배분에서 제외한다.
|
|
51
|
+
explicit 자식은 부모 auto 크기에 기여하지 않는다. 숨은 역방향 의존을 만들지 않는다.
|
|
52
|
+
|
|
53
|
+
## 3. 직렬화 계약의 골격
|
|
54
|
+
|
|
55
|
+
아래는 compiler 입력의 판별 union이다. 모든 생략 기본값은 정규화 시 정본에 기록한다.
|
|
56
|
+
길이 식은 하위 계약의 typed LengthExpr이며 문자열 JS 식을 허용하지 않는다.
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
type Axis = 'x' | 'y' | 'z'
|
|
60
|
+
type Measure =
|
|
61
|
+
| { kind: 'fixed'; value: LengthExpr }
|
|
62
|
+
| { kind: 'intrinsic' }
|
|
63
|
+
| { kind: 'parent'; fraction: number; offset: LengthExpr }
|
|
64
|
+
type Track =
|
|
65
|
+
| { kind: 'fixed'; value: LengthExpr }
|
|
66
|
+
| { kind: 'auto'; min: LengthExpr; max?: LengthExpr }
|
|
67
|
+
| { kind: 'fr'; weight: number; min: LengthExpr; max?: LengthExpr }
|
|
68
|
+
type Layout =
|
|
69
|
+
| { kind: 'flex'; axis: Axis; gap: LengthExpr;
|
|
70
|
+
justify: 'start' | 'center' | 'end' | 'space-between' }
|
|
71
|
+
| { kind: 'grid'; tracks: Record<Axis, Track[]>; gap: Record<Axis, LengthExpr> }
|
|
72
|
+
| { kind: 'explicit' }
|
|
73
|
+
type Fit =
|
|
74
|
+
| { kind: 'stretch'; axes: Axis[] }
|
|
75
|
+
| { kind: 'fixed' }
|
|
76
|
+
| { kind: 'contain'; allowUpscale: boolean }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
node에는 id, kind(container/shape), geometry 또는 layout, size[3], min[3], max[3],
|
|
80
|
+
padding[3][2], overflow(error/visible), children이 있다.
|
|
81
|
+
자식 배치에는 mode(flow/explicit), order(정수), 3축 align(start/center/end/stretch)이 있다.
|
|
82
|
+
Flex 자식은 basis(길이 또는 intrinsic), grow(0 이상 상수), shrinkWeight(0 이상 상수)를 갖는다.
|
|
83
|
+
Grid 자식은 각 축의 start(0 기반), span(양의 정수)를 갖는다. 자동 배치는 r1에 없다.
|
|
84
|
+
explicit 자식만 배치 driver(고정 transform 또는 feature 정렬)를 갖는다.
|
|
85
|
+
shape는 fit과 geometry-bound feature를 갖고, joint는 별도 motion 계약이다.
|
|
86
|
+
|
|
87
|
+
단일 writer의 구체적 적용: Flex 주축의 allocated-size는 basis/grow/shrink가 소유하므로
|
|
88
|
+
그 축의 별도 size driver는 허용하지 않는다. basis의 fixed는 시작 크기이며 최종 크기 고정이
|
|
89
|
+
아니다. 최종 크기 유지에는 grow=shrinkWeight=0을 사용한다.
|
|
90
|
+
Grid 트랙은 slot을 소유하며 item size/fit은 그 안의 형상 또는 중첩 컨테이너 크기를 소유한다.
|
|
91
|
+
여기서 intrinsic/preferred 값은 배분의 입력이고 allocated 값은 출력이므로 다른 값 노드다.
|
|
92
|
+
|
|
93
|
+
min 기본 0, max 생략은 제한 없음, grow/shrinkWeight 기본 0.
|
|
94
|
+
실제 geometry의 양수 하한/정의역은 geometry provider가 추가한다.
|
|
95
|
+
컨테이너 기본 overflow=error. visible은 사용자가 명시한 의도이며 검사 결과에 남긴다.
|
|
96
|
+
고정값/제한값의 단위, 참조, 유한성, min≤max, 식/노드 수 예산을 compile에서 검사한다.
|
|
97
|
+
논리적인 0 크기와 퇴화 geometry 허용 여부를 혼동하지 않는다.
|
|
98
|
+
|
|
99
|
+
## 4. Measure → Allocate → Arrange → Pose
|
|
100
|
+
|
|
101
|
+
```text
|
|
102
|
+
정본/geometry intrinsic metric
|
|
103
|
+
→ compile dependency DAG
|
|
104
|
+
→ Measure: 필요한 크기와 하한 측정
|
|
105
|
+
→ Allocate: 부모 content를 slot으로 분배
|
|
106
|
+
→ Arrange + Fit: slot 및 geometry 정지 frame 결정
|
|
107
|
+
→ Pose: joint 강체 변환
|
|
108
|
+
→ 동일 ResolvedLayout을 2D/3D/검사/내보내기에서 사용
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
단순한 “항상 아래부터 한 번, 위부터 한 번”은 일반 참조에서 충분하지 않다.
|
|
112
|
+
compiler는 measured-size, allocated-size, feature, position을 서로 다른 값 노드로 만들고
|
|
113
|
+
실제 의존 DAG의 위상 순서로 평가한다. 알고리즘 단계를 재귀적으로 반복해 수렴시키지 않는다.
|
|
114
|
+
|
|
115
|
+
intrinsic은 이전 프레임의 bounds가 아니다. geometry provider가 반환하는 명시적 저작 기준
|
|
116
|
+
치수 또는 자식의 intrinsic 측정값이다. 생성된 mesh 측정값을 원본 크기에 되먹이지 않는다.
|
|
117
|
+
leaf에 intrinsic이 없으면 오류다. 빈 컨테이너 intrinsic은 padding 합이다.
|
|
118
|
+
|
|
119
|
+
Flex intrinsic: 주축은 자식 basis 합 + gap × max(n-1,0) + padding,
|
|
120
|
+
교차축은 자식 preferred 크기의 최댓값 + padding.
|
|
121
|
+
Grid intrinsic: §6의 고정/최소/auto 측정 후 트랙 합 + gap + padding;
|
|
122
|
+
fr의 가중치 분배는 하지 않는다. fr 안의 내용이 더 크면 overflow일 수 있으며 진단한다.
|
|
123
|
+
max/min 적용은 명시된 box 정책이다. geometry의 종횡비나 표면을 몰래 수정하지 않는다.
|
|
124
|
+
|
|
125
|
+
parent 비율은 해당 부모 축이 독립적으로 결정된 경우에만 계산할 수 있다.
|
|
126
|
+
부모 intrinsic → 자식 parent 비율 → 부모 intrinsic의 순환은
|
|
127
|
+
`layout-cycle`로 거절하고 의존 경로를 보여준다. 0이나 직전 값으로 대체하지 않는다.
|
|
128
|
+
자식 fill/fr는 intrinsic 측정에서 부모의 미정 크기를 읽지 않고, min/intrinsic basis를
|
|
129
|
+
제공한 뒤 부모가 확정된 Allocate에서 남는 공간을 받는다.
|
|
130
|
+
|
|
131
|
+
순환 거절은 모든 순환식에 해가 없다는 주장이 아니다. 예를 들어 P=C+20, C=P/2는
|
|
132
|
+
P=40, C=20이라는 유일해가 있지만 r1은 이를 연립방정식으로 풀지 않는다.
|
|
133
|
+
범용 solver를 숨겨 넣지 않기 위한 지원 범위 결정이며, 진단에서 “수학적으로 불가능”이라고
|
|
134
|
+
설명해서는 안 된다. 부모 크기를 명시하거나 자식 비율 대신 고유 크기를 선택하도록 안내한다.
|
|
135
|
+
|
|
136
|
+
## 5. 3D Flex: 한 축의 제한된 공간 분배
|
|
137
|
+
|
|
138
|
+
줄바꿈은 r1에 없다. 자동 wrap은 크기에 따라 topology와 의미가 달라지므로 명시적 Grid/repeat로 작성한다.
|
|
139
|
+
주축 content 길이 L, 자식 n개, gap g. 사용 가능한 item 길이 A=L-g×max(n-1,0).
|
|
140
|
+
basis b_i를 [min_i,max_i]로 제한한 초기 크기를 B_i라 한다.
|
|
141
|
+
|
|
142
|
+
- A≥ΣB: grow weight w_i로 남는 공간을 배분한다.
|
|
143
|
+
x_i=B_i+min(max_i-B_i, λw_i).
|
|
144
|
+
- A<ΣB: shrinkWeight w_i로 줄일 공간을 배분한다.
|
|
145
|
+
x_i=B_i-min(B_i-min_i, λw_i).
|
|
146
|
+
- λ≥0이며 가능한 경우 Σx=A가 되게 한다. weight=0인 자식은 변하지 않는다.
|
|
147
|
+
- 용량이 포화된 자식은 고정하고 나머지에 남은 양을 재분배한다.
|
|
148
|
+
모든 자식이 포화되면 더 이상 변경하지 않는다.
|
|
149
|
+
- r1의 shrinkWeight는 **상수**다. CSS의 basis 가중 shrink를 암묵적으로 가져오지 않는다.
|
|
150
|
+
가변 basis로 가중치를 만들면 치수 결과가 유리함수가 되어 아핀 검증 범위가 달라진다.
|
|
151
|
+
|
|
152
|
+
양의 weight가 하나라도 활성인 구간에서 합계는 λ에 대해 엄격히 단조다.
|
|
153
|
+
해가 존재하면 x 벡터는 유일하다. 모두 포화된 뒤의 λ는 유일하지 않아도 x는 유일하다.
|
|
154
|
+
구현은 상한을 넘어간 항목을 동시에 freeze하며 최대 n번 활성 집합을 줄인다.
|
|
155
|
+
단순 구현 O(n²), breakpoint 정렬 구현 O(n log n). 반복 수렴 오차에 맡기지 않는다.
|
|
156
|
+
|
|
157
|
+
미분배 여유 F=max(0,A-Σx)는 justify로 처리한다.
|
|
158
|
+
start의 앞 여유 0, center F/2, end F.
|
|
159
|
+
space-between은 n>1일 때 추가 gap=F/(n-1), n=1이면 start로 정의한다.
|
|
160
|
+
n=0이면 아무 item도 배치하지 않는다.
|
|
161
|
+
|
|
162
|
+
content 왼쪽/아래/뒤 경계를 -L/2로 두면:
|
|
163
|
+
center_i = -L/2 + leading + Σ(j<i)(x_j+effectiveGap) + x_i/2.
|
|
164
|
+
|
|
165
|
+
공간 부족 A<Σx는 overflow다. 기본 error이며 자동 겹침/클리핑은 없다.
|
|
166
|
+
visible 정책에서는 계산된 위치를 반환하되 excess mm와 초과 방향을 노출한다.
|
|
167
|
+
부족 상태 justify는 start로 고정해 음수 gap이나 중앙에서 양쪽으로 튀는 숨은 보정을 막는다.
|
|
168
|
+
|
|
169
|
+
교차축은 각 slot이 content 전체를 사용한다. item의 start/center/end 또는 stretch를
|
|
170
|
+
각 축에서 독립 적용한다. stretch는 min/max로 제한하며 max로 남은 여유는 기본 center 정렬한다.
|
|
171
|
+
fixed 치수와 stretch writer를 동시에 선언하면 정규화 단계에서 충돌로 거절한다.
|
|
172
|
+
|
|
173
|
+
## 6. 3D Grid: 세 축의 트랙과 직육면체 slot
|
|
174
|
+
|
|
175
|
+
각 축의 트랙을 독립적으로 계산한다. 칸은 X/Y/Z 트랙 구간의 곱이다.
|
|
176
|
+
start/span이 범위를 벗어나면 오류다. 배열 순서로 빈 칸을 찾아 넣지 않는다.
|
|
177
|
+
기본적으로 두 flow item이 같은 3D 칸을 점유하면 오류다.
|
|
178
|
+
장식 겹침은 explicit 레이어로 작성하며 collision 검사는 별도다.
|
|
179
|
+
|
|
180
|
+
트랙 계산:
|
|
181
|
+
1. fixed는 지정 길이, auto/fr는 min으로 시작한다.
|
|
182
|
+
2. auto 트랙의 intrinsic 요구를 아래 규칙으로 누적한다.
|
|
183
|
+
3. content 길이에서 gap·fixed·auto·fr min을 뺀 남는 공간을 fr weight로
|
|
184
|
+
§5의 capped grow 연산을 사용해 배분한다.
|
|
185
|
+
4. 부족하면 기본 오류다. Grid의 fixed/auto를 암묵적으로 줄이지 않는다.
|
|
186
|
+
5. fr가 없거나 max로 전부 포화되면 남는 공간은 grid 정렬(start/center/end)로 처리한다.
|
|
187
|
+
|
|
188
|
+
단일 트랙 item은 auto의 하한을 preferred intrinsic까지 올린다.
|
|
189
|
+
여러 트랙에 걸친 item은 현재 트랙 합과 내부 gap을 뺀 부족분을,
|
|
190
|
+
그 span 안의 auto 트랙에 동등 weight로 max까지 분배한다.
|
|
191
|
+
처리 순서는 (span 길이, start 인덱스, 안정된 item id)다.
|
|
192
|
+
크기 기여만 처리하므로 한 축의 같은 구간을 여러 item이 요구해도 문제없다.
|
|
193
|
+
|
|
194
|
+
이 다중 span 규칙은 결정적인 구성 알고리즘이지 “가장 작은 모든 트랙의 최적해”가 아니다.
|
|
195
|
+
앞서 만족한 하한은 이후 증분 때문에 깨지지 않지만 불필요한 확대가 생길 수 있다.
|
|
196
|
+
배치 계약으로 그 결과를 명시한다. 최적화를 원하면 별도 목적함수/solver 계약이 필요하다.
|
|
197
|
+
max 때문에 아직 부족한 span은 즉시 최종 실패로 판단하지 않는다:
|
|
198
|
+
fr 배분이 끝난 뒤 실제 slot과 item의 min/fit 조건을 검사한다.
|
|
199
|
+
|
|
200
|
+
비율 트랙은 fixed 길이식에서 parent content의 상수배로 작성한다.
|
|
201
|
+
예: 50%+50%와 gap을 동시에 쓰면 넘친다. 남은 공간을 절반씩 나누려면 1fr+1fr를 쓴다.
|
|
202
|
+
X/Y/Z 각 축의 auto 측정이 다른 축의 배분에 의존하는 자동 종횡비 피드백은 r1에서 제외한다.
|
|
203
|
+
종횡비 보존은 이미 정해진 slot 안의 contain으로 처리한다.
|
|
204
|
+
|
|
205
|
+
## 7. Fit: 공간과 형상을 구분한다
|
|
206
|
+
|
|
207
|
+
slot 할당이 실제 형상의 비균등 확대를 뜻하지 않는다.
|
|
208
|
+
|
|
209
|
+
- fixed: geometry 치수를 유지하고 slot 안에 정렬한다.
|
|
210
|
+
- stretch: 지정한 축만 slot 크기를 따른다. geometry provider가 허용한 축만 가능하다.
|
|
211
|
+
원형 roller의 단면은 두 독립 축으로 stretch하지 않는다.
|
|
212
|
+
- contain: 기준 geometry size s₀와 상수 local 회전 Q에 대해
|
|
213
|
+
회전 bounds e=|Q|s₀를 구하고 k=min(slot_a/e_a)를 적용한다.
|
|
214
|
+
e_a=0 축은 양의 축만으로 비율을 계산하고 전부 0이면 퇴화 오류다.
|
|
215
|
+
allowUpscale=false면 k≤1. 양수 k와 geometry 정의역을 검사한다.
|
|
216
|
+
|
|
217
|
+
contain은 상자 포함의 보수적 fit이다. 비볼록 개구부의 내부 포함을 증명하지 않는다.
|
|
218
|
+
임의 회전 + 축별 stretch의 역문제는 r1에 없다. 컨테이너 축 정렬 또는 contain/fixed를 쓴다.
|
|
219
|
+
slot을 채웠다고 실제 표면이 맞닿는 것도 아니다. geometry-bound feature 부착/검사는 별도다.
|
|
220
|
+
|
|
221
|
+
상수 회전, 상수 intrinsic bounds의 contain은 유한한 min의 구간별 아핀이다.
|
|
222
|
+
intrinsic bounds 자체가 가변 길이에 의존하면 나눗셈이 발생하므로
|
|
223
|
+
이 경우 contain은 r1에서 거절한다. 명시적 고급 연산 없이 보장 범위를 넓히지 않는다.
|
|
224
|
+
|
|
225
|
+
## 8. 부착과 운동의 결합
|
|
226
|
+
|
|
227
|
+
일반 모델은 Flex/Grid 중첩으로 구성하고, 꼭 필요한 부착은 feature 정렬로 표현한다.
|
|
228
|
+
어떤 shape의 position을 flow가 이미 결정한다면 feature 부착을 추가로 쓰지 않는다.
|
|
229
|
+
그 shape를 explicit으로 전환하거나 wrapper의 위치를 feature에 붙인다.
|
|
230
|
+
|
|
231
|
+
layout tree와 motion forest는 별개지만 resolved rigid frame만 공유한다.
|
|
232
|
+
layout resize는 정지 위치를 재계산하며, 현재 joint 상태는 그 뒤 다시 적용한다.
|
|
233
|
+
부모의 비균등 scale matrix를 자식 motion에 전달하지 않는다.
|
|
234
|
+
정지 기준점 보존은 보장할 수 있지만 열린 문의 충돌/주차 공간은 별도 assertion이다.
|
|
235
|
+
|
|
236
|
+
## 9. 해와 검증의 수준
|
|
237
|
+
|
|
238
|
+
지원 언어에서 유효 DAG + 정의역 + 단일 writer + 명시적 overflow 정책이면
|
|
239
|
+
Measure/Allocate/Arrange는 종료하고 입력에 대해 하나의 결과 또는 구조화된 오류를 낸다.
|
|
240
|
+
overflow=error일 때 “항상 배치가 성공한다”는 보장은 아니다.
|
|
241
|
+
물리적으로 불가능한 요청을 실패로 표현하는 것도 계약이다.
|
|
242
|
+
|
|
243
|
+
Flex/Grid는 min/max, max intrinsic, 제한 배분 때문에 **구간별 아핀**이다.
|
|
244
|
+
고정 활성 집합 내부의 아핀 부등식은 영역 전체를 검증할 수 있다.
|
|
245
|
+
그러나 입력 box의 꼭짓점 검사만으로 내부 활성 집합 전환을 검증할 수는 없다.
|
|
246
|
+
|
|
247
|
+
검증 단계:
|
|
248
|
+
- 현재 치수: 모든 output의 finite/domain/writer/공간 예산 검사.
|
|
249
|
+
- 지원 범위: 연산별 sound interval 또는 활성 영역 분할로 보수적 증명.
|
|
250
|
+
- 영역 분할 예산을 초과하거나 비선형 geometry가 나오면 unverified 반환.
|
|
251
|
+
- 샘플은 tested이며 proven으로 승격하지 않는다. required 항목이 unverified이면
|
|
252
|
+
“실패 확정”이 아니라 “보장 미확인”으로 분리하고, 범위 축소/정책 선택을 제공한다.
|
|
253
|
+
- collision, 접촉면, 미적 품질은 layout 증명과 다른 검사다.
|
|
254
|
+
|
|
255
|
+
number 계산의 epsilon은 분기 비교에만 쓴다. 사용자의 clearance를 epsilon으로 없애지 않는다.
|
|
256
|
+
실제 실행의 float 결과 검사와 수학적인 실수 모델 증명은 구별한다.
|
|
257
|
+
증명 인증은 계수/구간의 보수적 반올림 구현이 있을 때만 제공한다.
|
|
258
|
+
r1 예제 테스트가 그런 인증 구현은 아니다.
|
|
259
|
+
|
|
260
|
+
## 10. 예제: 드라이룸과 선반 (실자산 검증 아님)
|
|
261
|
+
|
|
262
|
+
드라이룸:
|
|
263
|
+
- room 컨테이너: 폭/높이/깊이를 인스턴스에서 받음.
|
|
264
|
+
- portal wrapper: 앞면 feature에 배치; opening이 실제 portal 형상과 치수를 공유.
|
|
265
|
+
- opening의 X Flex: padding=10, gap=10, 문짝 두 개 min=0, basis=0, grow=1.
|
|
266
|
+
- 문짝 Y stretch, Z fixed 40. 두 문짝 width=(W-30)/2.
|
|
267
|
+
- 램프: portal 상단 feature에 explicit 부착, fixed 크기.
|
|
268
|
+
- 슬라이더: layout 후 문짝을 ±q(W-gap)/2 이동. lamp가 움직일지는 motion parent로 명시.
|
|
269
|
+
|
|
270
|
+
이것은 “바닥 아래 돌출을 자른다”의 자동 해석을 보장하지 않는다.
|
|
271
|
+
그 요청은 바닥이 어느 표면인지, portal의 상단을 유지할지 등을 현재 형상과 대조한
|
|
272
|
+
국소 편집으로 바꾸고 미리보기/승인해야 한다. 잘못된 모델을 layout만으로 복구했다고 주장하지 않는다.
|
|
273
|
+
|
|
274
|
+
선반:
|
|
275
|
+
- Y Grid에 선반 두께 fixed와 수납 공간 fr를 교대로 배치.
|
|
276
|
+
- 각 칸의 X Flex로 박스 배열. 램프는 해당 칸 frame에 정렬.
|
|
277
|
+
- repeat 개수 변화는 별도 topology 단계. 유한 budget, stable slot id, 삭제 영향 확인.
|
|
278
|
+
- r1 구현은 fixed count부터 시작하며 공간에 따라 count가 바뀌는 기능은 후속 단계다.
|
|
279
|
+
|
|
280
|
+
## 11. 성능·실행·편집 계약
|
|
281
|
+
|
|
282
|
+
Prepared에는 값 DAG, container 연산, feature binding, motion forest, geometry spec을 저장한다.
|
|
283
|
+
compile은 저작 변경 시, layout은 치수 변경 시, pose는 상태 변경 시만 수행한다.
|
|
284
|
+
매 frame 전체 layout 재계산을 하지 않는다. 컨테이너 수가 scene object 수가 되지 않는다.
|
|
285
|
+
|
|
286
|
+
DAG 비용 O(V+E)에 Flex 배분 O(n log n), Grid auto span의 방문 트랙 수와
|
|
287
|
+
각 배분 비용을 더한다. r1 prototype의 단순 water-fill은 O(n²)다.
|
|
288
|
+
잘못된 선형 시간 주장을 하지 않는다. AST 크기, depth, tracks, repeat count 예산을 둔다.
|
|
289
|
+
부모 치수 변경의 dirty propagation과 cache key에는 evaluator version을 포함한다.
|
|
290
|
+
layout 결과는 immutable이며 부분 오류 결과를 기존 장면에 덧붙이지 않는다.
|
|
291
|
+
|
|
292
|
+
UI: “가로 나열 / 칸 나누기 / 여백 / 간격 / 크기 유지 / 공간 채우기”.
|
|
293
|
+
고급 사용자는 계층과 고정/분배 정책을 편집한다. 기본 UI는 숫자식/anchor를 요구하지 않는다.
|
|
294
|
+
AI: 동일 typed transaction, sourceHash 사전조건, atomic apply, undo, 변경 근거와 검증 범위.
|
|
295
|
+
발행과 현재 초안 저장은 분리한다. 자동 수정은 레이아웃 의도를 삭제해서 통과시키지 않는다.
|
|
296
|
+
|
|
297
|
+
## 12. 출하 전 단계와 완료 기준
|
|
298
|
+
|
|
299
|
+
| 단계 | 범위 | 통과해야 할 검증 |
|
|
300
|
+
| --- | --- | --- |
|
|
301
|
+
| L0 설계 예제 | 제한 배분, Flex, fr, 회전 fit | 독립 기대값·경계·반례 테스트 |
|
|
302
|
+
| L1 production kernel | schema/DAG/measure/allocate/arrange | cycle, writer, NaN, overflow, 결정성, fuzz |
|
|
303
|
+
| L2 geometry/motion | 모든 지원 primitive의 치수·feature 계약 | bounds/개구부/normal, shear, pose 합성 |
|
|
304
|
+
| L3 modeller | 계층 편집·미리보기·undo·AI transaction | 원클릭 편집, 동시 변경, 오류 복구 E2E |
|
|
305
|
+
| L4 consumer/전환 | v2→v3 후보, 2D/3D 공통 결과 | 실제 드라이룸/롤 프레스, 회귀 스냅샷 |
|
|
306
|
+
| L5 비용/범위 | 1/100/500 instance, 범위 검증 | p95·draw call·메모리 실측, 증명 분류 |
|
|
307
|
+
|
|
308
|
+
r1은 레이아웃 규칙의 검토 가능한 기준안이다. 전체 v3 출하 명세/구현이 끝났다는 뜻이 아니다.
|
|
309
|
+
geometry별 feature catalog, 전체 JSON schema, 보수적 수치 증명기, renderer/consumer
|
|
310
|
+
전환 계약은 L1~L4에서 추가 고정해야 한다. 실제 사용자 조작 수와 결과 품질도 별도 측정한다.
|
|
311
|
+
|
|
312
|
+
### 현재 검증 기록
|
|
313
|
+
|
|
314
|
+
실행: `node --test docs/prototypes/v3-layout.test.mjs` — 18개 테스트 통과.
|
|
315
|
+
100개 문 폭의 간격/끝점, 800개 seed 고정 제한 배분 조합, fr/auto span,
|
|
316
|
+
회전 정렬/contain, branch 전환, 참조 순서/순환/중복 writer를 검증했다.
|
|
317
|
+
두짝문 travel=W/2라는 이전 예제의 오류를 발견해 (W-gap)/2로 수정했다.
|
|
318
|
+
코드와 한계를 [설계 검증 예제 설명](prototypes/README.md)에 기록했다.
|