@ssafy-mhk/e-ver 1.0.3 → 1.0.4
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 +175 -120
- package/dist/api/EverClient.d.ts +12 -1
- package/dist/avatar/VRMCompat.d.ts +8 -0
- package/dist/avatar/avatarLoader.d.ts +12 -0
- package/dist/avatar/humanoidBindings.d.ts +7 -0
- package/dist/bodyPreset/presetSelection.d.ts +31 -0
- package/dist/components/CameraView.d.ts +5 -0
- package/dist/components/EverCanvas.d.ts +2 -0
- package/dist/components/EverFittingScene.d.ts +18 -0
- package/dist/components/EverFittingScene.test.d.ts +1 -0
- package/dist/components/EverTrackedGarment.d.ts +15 -0
- package/dist/components/TrackedGarmentPoseDriver.d.ts +13 -0
- package/dist/components/WebcamPlaneBackground.d.ts +7 -0
- package/dist/compositing/videoCover.d.ts +14 -0
- package/dist/fitting/bodyFirstFitting.d.ts +14 -0
- package/dist/fitting/bodyFirstFitting.test.d.ts +1 -0
- package/dist/garment/constants.d.ts +1 -0
- package/dist/garment/fitMotion.d.ts +18 -0
- package/dist/garment/garmentFitProfile.d.ts +24 -0
- package/dist/garment/poseApplication.d.ts +18 -0
- package/dist/garment/trackedGarmentMotion.d.ts +32 -0
- package/dist/garment/trackedModelTransform.d.ts +40 -0
- package/dist/hooks/useAvatarVariant.d.ts +12 -0
- package/dist/hooks/useBodyMeasurer.d.ts +13 -4
- package/dist/hooks/useBodyPresetSelection.d.ts +3 -0
- package/dist/hooks/useEverFitting.d.ts +51 -0
- package/dist/hooks/useEverFitting.test.d.ts +1 -0
- package/dist/hooks/useEverGeneration.d.ts +4 -5
- package/dist/hooks/useMeasurement.d.ts +19 -0
- package/dist/hooks/usePoseMapper.d.ts +2 -7
- package/dist/hooks/usePoseTracker.d.ts +24 -6
- package/dist/hooks/useWebcam.d.ts +19 -0
- package/dist/hooks/useWebcam.test.d.ts +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.es.js +3119 -40592
- package/dist/index.umd.js +1 -4415
- package/dist/measurement/garmentScaler.d.ts +19 -0
- package/dist/measurement/scaleCalculator.d.ts +5 -0
- package/dist/measurement/scaleCalculator.test.d.ts +1 -0
- package/dist/measurement/silhouetteExtractor.d.ts +3 -0
- package/dist/measurement/sizeRecommender.d.ts +2 -0
- package/dist/pose/boneMapping.d.ts +14 -0
- package/dist/pose/coordinateTransform.d.ts +9 -0
- package/dist/pose/facingDetector.d.ts +35 -0
- package/dist/pose/interpolation.d.ts +16 -0
- package/dist/pose/landmarkPoseSolver.d.ts +9 -0
- package/dist/pose/landmarkerFactory.d.ts +13 -0
- package/dist/pose/poseSolver.d.ts +2 -0
- package/dist/pose/segmentation.d.ts +9 -0
- package/dist/pose/smoothing.d.ts +12 -0
- package/dist/pose/yawDirectionStabilizer.d.ts +20 -0
- package/dist/pose/yawFreezeController.d.ts +11 -0
- package/dist/publicApi.test.d.ts +1 -0
- package/dist/store/useEverStore.d.ts +2 -4
- package/dist/tracking/personLock.d.ts +39 -0
- package/dist/tracking/trackingStability.d.ts +6 -0
- package/dist/tracking/trackingState.d.ts +18 -0
- package/dist/types/bodyPreset.d.ts +65 -0
- package/dist/types/fitting.d.ts +15 -0
- package/dist/types/measurement.d.ts +42 -0
- package/dist/types/pose.d.ts +81 -0
- package/dist/types/tracking.d.ts +13 -0
- package/package.json +8 -5
package/README.md
CHANGED
|
@@ -1,189 +1,244 @@
|
|
|
1
|
-
# `@ssafy-mhk/e-ver`
|
|
1
|
+
# `@ssafy-mhk/e-ver`
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
복잡한 Three.js 카메라 및 조명 설정, MediaPipe AI 바디 트래킹 연동, SkinnedMesh 기반 의류 렌더링 로직을 추상화하여, **단순한 React 컴포넌트와 Hook**으로 증강현실(AR) 가상 피팅 기능을 빠르게 구현할 수 있도록 지원합니다.
|
|
3
|
+
React 기반 가상 피팅 SDK입니다. `generate-3d`로 생성한 의류 GLB를 불러오고, 웹캠과 MediaPipe Pose 추적을 이용해 body preset 기반 가상 피팅 씬을 구성할 수 있습니다.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
현재 SDK가 책임지는 범위는 다음입니다.
|
|
7
6
|
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
7
|
+
- 의류 생성 API client와 생성 플로우
|
|
8
|
+
- webcam, pose tracking, body measurement, body preset selection
|
|
9
|
+
- tracked garment 렌더링
|
|
10
|
+
- 최종 보정이 반영된 `finalGarmentScale` 계산
|
|
12
11
|
|
|
13
|
-
|
|
12
|
+
현재 SDK가 책임지지 않는 범위는 다음입니다.
|
|
14
13
|
|
|
15
|
-
|
|
14
|
+
- 패널 UI, 디버그 UI, overlay
|
|
15
|
+
- foreground occlusion 같은 앱 전용 시각 효과
|
|
16
|
+
- 사진 기반 개인 avatar 생성
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
### 배포된 패키지 설치
|
|
20
|
-
|
|
21
|
-
여러분의 Next.js 프로젝트 최상위 폴더에서 아래 명령어를 실행하세요.
|
|
18
|
+
## 설치
|
|
22
19
|
|
|
23
20
|
```bash
|
|
24
|
-
# pnpm 사용 시
|
|
25
21
|
pnpm add @ssafy-mhk/e-ver
|
|
26
|
-
|
|
27
|
-
# 또는 패키지 매니저에 따라
|
|
28
|
-
npm install @ssafy-mhk/e-ver
|
|
29
|
-
yarn add @ssafy-mhk/e-ver
|
|
30
22
|
```
|
|
31
23
|
|
|
32
|
-
|
|
24
|
+
필수 peer dependency:
|
|
33
25
|
|
|
34
|
-
|
|
26
|
+
```bash
|
|
27
|
+
pnpm add react react-dom three @react-three/fiber @react-three/drei @mediapipe/tasks-vision zustand
|
|
28
|
+
```
|
|
35
29
|
|
|
36
|
-
|
|
30
|
+
이 레포에서 `ever/frontend`로 로컬 검증할 때는:
|
|
37
31
|
|
|
38
32
|
```bash
|
|
39
33
|
pnpm run sdk:use-tarball
|
|
40
34
|
```
|
|
41
35
|
|
|
42
|
-
|
|
36
|
+
퍼블리시된 버전으로 되돌릴 때는:
|
|
43
37
|
|
|
44
38
|
```bash
|
|
45
|
-
pnpm run sdk:use-version -- 1.0.
|
|
39
|
+
pnpm run sdk:use-version -- 1.0.4
|
|
46
40
|
```
|
|
47
41
|
|
|
48
|
-
|
|
42
|
+
## 서버와 인증
|
|
43
|
+
|
|
44
|
+
기본 API 서버는 `http://localhost:8000/api/v1`입니다.
|
|
49
45
|
|
|
50
|
-
|
|
46
|
+
```tsx
|
|
47
|
+
import { EverClient } from "@ssafy-mhk/e-ver";
|
|
51
48
|
|
|
52
|
-
|
|
49
|
+
const client = new EverClient();
|
|
53
50
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
| **Renderer** | `AvatarModel` | 사용자의 AI 기반 생성 3D 아바타(GLB)를 로딩하고, 뼈대(Bone) 구조를 추출 |
|
|
59
|
-
| **Renderer** | `GarmentModel` | 사용자가 선택한 옷(GLB)을 로딩하고, 옷의 SkinnedMesh를 대상 아바타에 입힘 |
|
|
60
|
-
| **Tracker** | `usePoseTracker` | 브라우저 내에서 MediaPipe를 가동시켜 실시간 30-60Hz 웹캠 추적 |
|
|
61
|
-
| **Tracker** | `usePoseMapper` | 웹캠에서 얻은 2D/3D 점(Landmarks)을 필수 13본(Bone)의 회전값(Quaternion)으로 변환 |
|
|
62
|
-
| **Tracker** | `useBodyMeasurer` | AR 카메라 상에서 사용자 실루엣 기반 사이즈(어깨, 가슴, 허리)를 연산하여 옷의 핏 평가 |
|
|
51
|
+
const publicClient = new EverClient({
|
|
52
|
+
apiKey: "ever_live_xxxxxxxx",
|
|
53
|
+
});
|
|
54
|
+
```
|
|
63
55
|
|
|
64
|
-
|
|
56
|
+
- 기본 생성자: 쿠키 인증 또는 같은 오리진 환경에서 사용
|
|
57
|
+
- `apiKey` 지정 시: `/sdk/public/*` 경로를 사용하는 공개 SDK 모드
|
|
65
58
|
|
|
66
|
-
|
|
59
|
+
`useEverGeneration`도 동일하게 `apiKey`를 받을 수 있습니다.
|
|
67
60
|
|
|
68
|
-
|
|
61
|
+
## 권장 사용 흐름
|
|
69
62
|
|
|
70
|
-
|
|
63
|
+
가장 권장되는 경로는 아래입니다.
|
|
71
64
|
|
|
72
|
-
|
|
65
|
+
1. `useEverGeneration`으로 의류 생성
|
|
66
|
+
2. 생성이 끝나면 `resultUrl` 확보
|
|
67
|
+
3. `EverFittingScene`에 `garmentUrl={resultUrl}` 전달
|
|
68
|
+
4. `onRuntimeStateChange`에서 `measurements`, `bodyPresetSelection`, `finalGarmentScale` 소비
|
|
69
|
+
|
|
70
|
+
## 핵심 API
|
|
71
|
+
|
|
72
|
+
| 분류 | 모듈 | 역할 |
|
|
73
|
+
| --- | --- | --- |
|
|
74
|
+
| Client | `EverClient` | body preset 조회/매칭, garment 생성, 이미지 업로드, `generate-3d`, polling |
|
|
75
|
+
| Hook | `useEverGeneration` | 의류 생성 플로우를 훅으로 제공 |
|
|
76
|
+
| Scene | `EverFittingScene` | webcam, tracking, measurement, body preset selection, garment 렌더링 통합 |
|
|
77
|
+
| Scene | `EverTrackedGarment` | 준비된 의류 GLB를 추적 렌더링 |
|
|
78
|
+
| Hook | `useEverFitting` | 고수준 fitting runtime 상태 제공 |
|
|
79
|
+
| Hook | `useBodyPresetSelection` | 측정값 기반 body preset 자동 선택 |
|
|
80
|
+
| Renderer | `EverCanvas` | 저수준 R3F canvas wrapper |
|
|
81
|
+
|
|
82
|
+
## Quick Start
|
|
73
83
|
|
|
74
84
|
```tsx
|
|
75
|
-
|
|
76
|
-
"use client";
|
|
85
|
+
import { EverFittingScene, useEverGeneration } from "@ssafy-mhk/e-ver";
|
|
77
86
|
|
|
78
|
-
|
|
87
|
+
function Demo() {
|
|
88
|
+
const { createGarment, resultUrl, status } = useEverGeneration({
|
|
89
|
+
apiKey: process.env.NEXT_PUBLIC_EVER_API_KEY,
|
|
90
|
+
});
|
|
79
91
|
|
|
80
|
-
|
|
81
|
-
|
|
92
|
+
const handleGenerate = async () => {
|
|
93
|
+
await createGarment(
|
|
94
|
+
{ name: "오버핏 셔츠", category: "top" },
|
|
95
|
+
frontImageBlob,
|
|
96
|
+
backImageBlob,
|
|
97
|
+
);
|
|
98
|
+
};
|
|
82
99
|
|
|
83
100
|
return (
|
|
84
|
-
<div className="
|
|
85
|
-
<button onClick={
|
|
86
|
-
|
|
87
|
-
새로운 옷 입어보기 👕
|
|
101
|
+
<div className="relative h-screen w-full">
|
|
102
|
+
<button onClick={handleGenerate} disabled={status !== "idle"}>
|
|
103
|
+
3D 생성
|
|
88
104
|
</button>
|
|
89
105
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
<EverFittingScene
|
|
107
|
+
garmentUrl={resultUrl}
|
|
108
|
+
enabled
|
|
109
|
+
measurementEnabled
|
|
110
|
+
autoStartMeasurement
|
|
111
|
+
fitType="regular"
|
|
112
|
+
onRuntimeStateChange={(runtime) => {
|
|
113
|
+
console.log(runtime.measurements);
|
|
114
|
+
console.log(runtime.bodyPresetSelection);
|
|
115
|
+
console.log(runtime.finalGarmentScale);
|
|
116
|
+
}}
|
|
117
|
+
/>
|
|
95
118
|
</div>
|
|
96
119
|
);
|
|
97
120
|
}
|
|
98
121
|
```
|
|
99
122
|
|
|
100
|
-
|
|
123
|
+
## 생성 API
|
|
101
124
|
|
|
102
|
-
|
|
125
|
+
### `useEverGeneration`
|
|
103
126
|
|
|
104
|
-
|
|
105
|
-
// components/VirtualFittingScene.tsx
|
|
106
|
-
"use client";
|
|
127
|
+
`createGarment`는 아래 순서를 묶습니다.
|
|
107
128
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
GarmentModel,
|
|
113
|
-
useEverStore,
|
|
114
|
-
} from "@ssafy-mhk/e-ver";
|
|
129
|
+
1. garment 생성
|
|
130
|
+
2. front/back 이미지 업로드
|
|
131
|
+
3. `generate-3d` 요청
|
|
132
|
+
4. 의류 모델 준비 완료까지 polling
|
|
115
133
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
const { activeGarmentUrl } = useEverStore();
|
|
134
|
+
```tsx
|
|
135
|
+
import { useEverGeneration } from "@ssafy-mhk/e-ver";
|
|
119
136
|
|
|
120
|
-
|
|
121
|
-
const
|
|
137
|
+
function Generator() {
|
|
138
|
+
const { createGarment, resultUrl, status, error } = useEverGeneration();
|
|
122
139
|
|
|
123
140
|
return (
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
</EverCanvas>
|
|
141
|
-
</div>
|
|
141
|
+
<>
|
|
142
|
+
<button
|
|
143
|
+
onClick={() =>
|
|
144
|
+
createGarment(
|
|
145
|
+
{ name: "니트", category: "top" },
|
|
146
|
+
frontImageBlob,
|
|
147
|
+
backImageBlob,
|
|
148
|
+
)
|
|
149
|
+
}
|
|
150
|
+
>
|
|
151
|
+
생성
|
|
152
|
+
</button>
|
|
153
|
+
<p>{status}</p>
|
|
154
|
+
{error ? <p>{error}</p> : null}
|
|
155
|
+
{resultUrl ? <p>{resultUrl}</p> : null}
|
|
156
|
+
</>
|
|
142
157
|
);
|
|
143
158
|
}
|
|
144
159
|
```
|
|
145
160
|
|
|
146
|
-
|
|
161
|
+
## 고수준 Scene
|
|
147
162
|
|
|
148
|
-
|
|
163
|
+
### `EverFittingScene`
|
|
149
164
|
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
165
|
+
가장 권장되는 엔트리입니다. 내부에서 다음을 수행합니다.
|
|
166
|
+
|
|
167
|
+
- webcam 준비
|
|
168
|
+
- MediaPipe Pose tracking
|
|
169
|
+
- 측정값 계산
|
|
170
|
+
- body preset 선택
|
|
171
|
+
- tracked garment 렌더링
|
|
172
|
+
- 최종 보정 scale 계산
|
|
173
|
+
|
|
174
|
+
주요 props:
|
|
175
|
+
|
|
176
|
+
- `garmentUrl: string | null`
|
|
177
|
+
- `enabled?: boolean`
|
|
178
|
+
- `measurementEnabled?: boolean`
|
|
179
|
+
- `autoStartMeasurement?: boolean`
|
|
180
|
+
- `fitType?: "slim" | "regular" | "oversize"`
|
|
181
|
+
- `garmentScaleHint?: number | null`
|
|
182
|
+
- `onRuntimeStateChange?: (runtime) => void`
|
|
183
|
+
- `onGarmentLoadStateChange?: (state) => void`
|
|
184
|
+
|
|
185
|
+
`runtime`에서 특히 많이 쓰는 값:
|
|
186
|
+
|
|
187
|
+
- `measurements`
|
|
188
|
+
- `bodyPresetSelection`
|
|
189
|
+
- `sizeRecommendation`
|
|
190
|
+
- `garmentScale`
|
|
191
|
+
- `finalGarmentScale`
|
|
192
|
+
- `bodyMorphResult`
|
|
193
|
+
- `isTracking`
|
|
194
|
+
- `webcamError`
|
|
153
195
|
|
|
154
|
-
|
|
155
|
-
import { usePoseTracker, useEverStore } from "@ssafy-mhk/e-ver";
|
|
196
|
+
## 저수준 조립
|
|
156
197
|
|
|
157
|
-
|
|
158
|
-
const videoRef = useRef<HTMLVideoElement>(null);
|
|
198
|
+
직접 조립이 필요하면 `useEverFitting`과 `EverTrackedGarment`를 사용할 수 있습니다.
|
|
159
199
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
200
|
+
```tsx
|
|
201
|
+
import { EverCanvas, EverTrackedGarment, useEverFitting } from "@ssafy-mhk/e-ver";
|
|
202
|
+
|
|
203
|
+
function CustomScene({ garmentUrl }: { garmentUrl: string }) {
|
|
204
|
+
const fitting = useEverFitting({
|
|
205
|
+
enabled: true,
|
|
206
|
+
fitType: "oversize",
|
|
207
|
+
garmentScaleHint: 1.04,
|
|
208
|
+
});
|
|
163
209
|
|
|
164
210
|
return (
|
|
165
|
-
<
|
|
166
|
-
<
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
style={{ display: isWebcamActive ? "block" : "none" }}
|
|
211
|
+
<EverCanvas showEnvironment={false}>
|
|
212
|
+
<EverTrackedGarment
|
|
213
|
+
url={garmentUrl}
|
|
214
|
+
landmarks={fitting.landmarks}
|
|
215
|
+
worldLandmarks={fitting.worldLandmarks}
|
|
216
|
+
poseFrameWidth={fitting.poseFrameWidth}
|
|
217
|
+
poseFrameHeight={fitting.poseFrameHeight}
|
|
173
218
|
/>
|
|
174
|
-
|
|
175
|
-
{!isTrackerReady && isWebcamActive && <p>AI 모델 로딩 중...</p>}
|
|
176
|
-
</div>
|
|
219
|
+
</EverCanvas>
|
|
177
220
|
);
|
|
178
221
|
}
|
|
179
222
|
```
|
|
180
223
|
|
|
181
|
-
|
|
224
|
+
## fitting 결과
|
|
225
|
+
|
|
226
|
+
`finalGarmentScale`은 아래 요소를 합성한 최종 결과입니다.
|
|
227
|
+
|
|
228
|
+
- body measurement 기반 scale
|
|
229
|
+
- body preset selection
|
|
230
|
+
- `fitType`
|
|
231
|
+
- `garmentScaleHint`
|
|
232
|
+
|
|
233
|
+
showcase와 동일한 fitting 결과가 필요하면 소비 앱에서 별도 보정하지 말고 `runtime.finalGarmentScale`을 그대로 사용하면 됩니다.
|
|
234
|
+
|
|
235
|
+
## 주의 사항
|
|
182
236
|
|
|
183
|
-
|
|
237
|
+
**`generateAvatar`는 사진 기반 개인 avatar 생성이 아닙니다.**
|
|
238
|
+
현재 버전에서는 body preset 매칭을 통해 기본 아바타 모델 URL을 찾습니다.
|
|
184
239
|
|
|
185
|
-
**
|
|
186
|
-
|
|
240
|
+
**SDK는 UI kit이 아닙니다.**
|
|
241
|
+
측정 패널, 디버그 패널, overlay는 소비 앱에서 조립해야 합니다.
|
|
187
242
|
|
|
188
|
-
**
|
|
189
|
-
|
|
243
|
+
**SDK 범위는 body preset 기반 fitting입니다.**
|
|
244
|
+
개인 사진 기반 avatar 생성이나 앱 전용 시각 효과는 현재 범위 밖입니다.
|
package/dist/api/EverClient.d.ts
CHANGED
|
@@ -138,13 +138,24 @@ export interface WaitForGarmentModelOptions {
|
|
|
138
138
|
intervalMs?: number;
|
|
139
139
|
timeoutMs?: number;
|
|
140
140
|
}
|
|
141
|
+
export interface EverClientOptions {
|
|
142
|
+
baseUrl?: string;
|
|
143
|
+
apiKey?: string;
|
|
144
|
+
}
|
|
145
|
+
export declare const DEFAULT_EVER_API_BASE_URL = "http://localhost:8000/api/v1";
|
|
141
146
|
/**
|
|
142
147
|
* EverClient provides methods to interact with the e-ver backend API.
|
|
148
|
+
*
|
|
149
|
+
* Supports two authentication modes:
|
|
150
|
+
* - **Cookie (default)**: browser session credentials (no apiKey).
|
|
151
|
+
* - **API Key**: pass `apiKey` in the constructor to use `X-API-Key` header
|
|
152
|
+
* and route requests through `/sdk/public/*` endpoints.
|
|
143
153
|
*/
|
|
144
154
|
export declare class EverClient {
|
|
145
155
|
private readonly baseUrl;
|
|
146
156
|
private readonly apiOrigin;
|
|
147
|
-
|
|
157
|
+
private readonly apiKey;
|
|
158
|
+
constructor(config?: string | EverClientOptions);
|
|
148
159
|
resolveAssetUrl(assetUrl: string | null): string | null;
|
|
149
160
|
listBodyPresets(gender?: string): Promise<BodyPreset[]>;
|
|
150
161
|
matchBodyPreset(body: BodyPresetMatchRequest): Promise<BodyPreset>;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { VRM } from "@pixiv/three-vrm";
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
export interface VRMCompatHumanoid {
|
|
4
|
+
getNormalizedBoneNode(boneName: string): THREE.Object3D | null;
|
|
5
|
+
update(delta: number): void;
|
|
6
|
+
vrm: VRM | null;
|
|
7
|
+
}
|
|
8
|
+
export declare function createVRMCompat(scene: THREE.Object3D, vrm: VRM | null | undefined): VRMCompatHumanoid;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { VRM } from "@pixiv/three-vrm";
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
type UseGLTFSignature = typeof import("@react-three/drei")["useGLTF"];
|
|
4
|
+
type AvatarLoader = Parameters<NonNullable<Parameters<UseGLTFSignature>[3]>>[0];
|
|
5
|
+
export type AvatarAssetKind = "vrm" | "gltf";
|
|
6
|
+
export declare function isVRMAssetUrl(url: string): boolean;
|
|
7
|
+
export declare function getAvatarAssetKind(url: string): AvatarAssetKind;
|
|
8
|
+
export declare function configureAvatarLoader(loader: AvatarLoader, url: string): void;
|
|
9
|
+
export declare function createAvatarLoaderExtension(url: string): ((loader: AvatarLoader) => void) | undefined;
|
|
10
|
+
export declare function prepareAvatarScene(scene: THREE.Object3D): void;
|
|
11
|
+
export declare function prepareNativeVRM(vrm: VRM): void;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
import { type GarmentBoneBindingMap } from "../garment/garmentFitProfile";
|
|
3
|
+
interface HumanoidBoneSource {
|
|
4
|
+
getNormalizedBoneNode(name: string): THREE.Object3D | null;
|
|
5
|
+
}
|
|
6
|
+
export declare function createHumanoidBoneBindings(humanoid: HumanoidBoneSource): GarmentBoneBindingMap;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { EverClient } from "../api/EverClient";
|
|
2
|
+
import type { BodyPreset } from "../api/EverClient";
|
|
3
|
+
import type { BodyMeasurements } from "../types/measurement";
|
|
4
|
+
import type { BodyPresetGender, BodyPresetMatchRequest, BodyPresetSelection, BodyPresetSummary } from "../types/bodyPreset";
|
|
5
|
+
export declare const DEFAULT_MALE_BODY_PRESET_ID = "male-m-balanced-balanced";
|
|
6
|
+
export declare const DEFAULT_FEMALE_BODY_PRESET_ID = "female-m-balanced-balanced";
|
|
7
|
+
export declare const LEGACY_RIGGED_BODY_PRESET_ID = "rigged_avatar";
|
|
8
|
+
export declare function normalizeBodyPresetGender(value?: string | null): BodyPresetGender;
|
|
9
|
+
export declare function buildBodyPresetAssetUrl(presetId: string, options?: {
|
|
10
|
+
renderMode?: "rigged_avatar" | "preset-native";
|
|
11
|
+
legacyPresetId?: string;
|
|
12
|
+
}): string;
|
|
13
|
+
export declare function getDefaultBodyPresetId(gender: BodyPresetGender): string;
|
|
14
|
+
export declare function toBodyPresetSummary(preset: BodyPreset, client: EverClient): BodyPresetSummary;
|
|
15
|
+
export declare function ensureBodyPresetModelUrl(preset: BodyPresetSummary, options?: {
|
|
16
|
+
renderMode?: "rigged_avatar" | "preset-native";
|
|
17
|
+
legacyPresetId?: string;
|
|
18
|
+
}): BodyPresetSummary;
|
|
19
|
+
export declare function pickDefaultBodyPreset(presets: BodyPresetSummary[], options?: {
|
|
20
|
+
renderMode?: "rigged_avatar" | "preset-native";
|
|
21
|
+
legacyPresetId?: string;
|
|
22
|
+
}): BodyPresetSummary | null;
|
|
23
|
+
export declare function createFallbackBodyPresetSelection(gender: BodyPresetGender, options?: {
|
|
24
|
+
renderMode?: "rigged_avatar" | "preset-native";
|
|
25
|
+
legacyPresetId?: string;
|
|
26
|
+
}): BodyPresetSelection;
|
|
27
|
+
export declare function toBodyPresetSelection(preset: BodyPresetSummary, source: BodyPresetSelection["source"], options?: {
|
|
28
|
+
renderMode?: "rigged_avatar" | "preset-native";
|
|
29
|
+
legacyPresetId?: string;
|
|
30
|
+
}): BodyPresetSelection;
|
|
31
|
+
export declare function buildBodyPresetMatchRequest(measurements: BodyMeasurements, gender: BodyPresetGender): BodyPresetMatchRequest;
|
|
@@ -2,6 +2,11 @@ import React from "react";
|
|
|
2
2
|
export interface CameraViewProps {
|
|
3
3
|
className?: string;
|
|
4
4
|
style?: React.CSSProperties;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
facingMode?: "user" | "environment";
|
|
8
|
+
enabled?: boolean;
|
|
9
|
+
mockMode?: boolean;
|
|
5
10
|
}
|
|
6
11
|
/**
|
|
7
12
|
* CameraView handles the rendering of the user's webcam feed.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type CSSProperties } from "react";
|
|
2
|
+
import type { UseBodyPresetSelectionOptions } from "../types/bodyPreset";
|
|
3
|
+
import { type EverFittingOptions, type EverFittingRuntimeState } from "../hooks/useEverFitting";
|
|
4
|
+
import { type GarmentLoadState } from "./EverTrackedGarment";
|
|
5
|
+
export interface EverFittingSceneProps extends Pick<EverFittingOptions, "enabled" | "width" | "height" | "facingMode" | "mockMode" | "viewportWidth" | "viewportHeight" | "measurementEnabled" | "autoStartMeasurement" | "measurementConfig" | "fitType" | "garmentScaleHint"> {
|
|
6
|
+
garmentUrl: string | null;
|
|
7
|
+
bodyPresetOptions?: UseBodyPresetSelectionOptions;
|
|
8
|
+
className?: string;
|
|
9
|
+
style?: CSSProperties;
|
|
10
|
+
debugMaterials?: boolean;
|
|
11
|
+
showEnvironment?: boolean;
|
|
12
|
+
showStats?: boolean;
|
|
13
|
+
showWebcamBackground?: boolean;
|
|
14
|
+
onCanvasReadyChange?: (ready: boolean) => void;
|
|
15
|
+
onRuntimeStateChange?: (state: EverFittingRuntimeState) => void;
|
|
16
|
+
onGarmentLoadStateChange?: (state: GarmentLoadState) => void;
|
|
17
|
+
}
|
|
18
|
+
export declare function EverFittingScene({ garmentUrl, enabled, width, height, facingMode, mockMode, viewportWidth, viewportHeight, measurementEnabled, autoStartMeasurement, measurementConfig, fitType, garmentScaleHint, bodyPresetOptions, className, style, debugMaterials, showEnvironment, showStats, showWebcamBackground, onCanvasReadyChange, onRuntimeStateChange, onGarmentLoadStateChange, }: EverFittingSceneProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { PoseLandmarkLike } from "../types/pose";
|
|
2
|
+
export interface GarmentLoadState {
|
|
3
|
+
loaded: boolean;
|
|
4
|
+
error: string | null;
|
|
5
|
+
}
|
|
6
|
+
export interface EverTrackedGarmentProps {
|
|
7
|
+
url: string;
|
|
8
|
+
landmarks: PoseLandmarkLike[] | null;
|
|
9
|
+
worldLandmarks: PoseLandmarkLike[] | null;
|
|
10
|
+
poseFrameWidth: number;
|
|
11
|
+
poseFrameHeight: number;
|
|
12
|
+
debugMaterials?: boolean;
|
|
13
|
+
onLoadStateChange?: (state: GarmentLoadState) => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function EverTrackedGarment({ url, landmarks, worldLandmarks, poseFrameWidth, poseFrameHeight, debugMaterials, onLoadStateChange, }: EverTrackedGarmentProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { NormalizedLandmark } from "@mediapipe/tasks-vision";
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
import type { GarmentBoneBindingMap, GarmentFitProfile } from "../garment/garmentFitProfile";
|
|
4
|
+
export interface TrackedGarmentPoseDriverProps {
|
|
5
|
+
garmentRootRef: React.RefObject<THREE.Group | null>;
|
|
6
|
+
boneBindingMap: GarmentBoneBindingMap;
|
|
7
|
+
fitProfile: GarmentFitProfile | null;
|
|
8
|
+
landmarks: NormalizedLandmark[] | null;
|
|
9
|
+
worldLandmarks: NormalizedLandmark[] | null;
|
|
10
|
+
poseFrameWidth: number;
|
|
11
|
+
poseFrameHeight: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function TrackedGarmentPoseDriver({ garmentRootRef, boneBindingMap, fitProfile, landmarks, worldLandmarks, poseFrameWidth, poseFrameHeight, }: TrackedGarmentPoseDriverProps): null;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type RefObject } from "react";
|
|
2
|
+
interface WebcamPlaneBackgroundProps {
|
|
3
|
+
videoRef: RefObject<HTMLVideoElement | null>;
|
|
4
|
+
webcamReady: boolean;
|
|
5
|
+
}
|
|
6
|
+
export declare function WebcamPlaneBackground({ videoRef, webcamReady, }: WebcamPlaneBackgroundProps): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export interface VisibleNormalizedRegion {
|
|
2
|
+
xMin: number;
|
|
3
|
+
xMax: number;
|
|
4
|
+
yMin: number;
|
|
5
|
+
yMax: number;
|
|
6
|
+
}
|
|
7
|
+
export interface CoverRect {
|
|
8
|
+
x: number;
|
|
9
|
+
y: number;
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
}
|
|
13
|
+
export declare function computeCoverRect(viewportWidth: number, viewportHeight: number, sourceWidth: number, sourceHeight: number): CoverRect;
|
|
14
|
+
export declare function computeVisibleNormalizedRegion(viewportWidth: number, viewportHeight: number, sourceWidth: number, sourceHeight: number): VisibleNormalizedRegion;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { type GarmentSpec } from "../measurement/garmentScaler";
|
|
2
|
+
import type { BodyPresetSelection } from "../types/bodyPreset";
|
|
3
|
+
import type { BodyFirstFittingResult, BodyMorphResult, FitType } from "../types/fitting";
|
|
4
|
+
import type { BodyMeasurements, GarmentScaleParams } from "../types/measurement";
|
|
5
|
+
export interface BodyFirstFittingParams {
|
|
6
|
+
measurements: BodyMeasurements | null;
|
|
7
|
+
measurementScale: GarmentScaleParams | null;
|
|
8
|
+
presetSelection: BodyPresetSelection | null;
|
|
9
|
+
fitType?: FitType;
|
|
10
|
+
garmentScaleHint?: number | null;
|
|
11
|
+
spec?: GarmentSpec;
|
|
12
|
+
}
|
|
13
|
+
export declare function deriveBodyMorphResult(measurements: BodyMeasurements, presetSelection: BodyPresetSelection): BodyMorphResult;
|
|
14
|
+
export declare function computeBodyFirstFitting({ measurements, measurementScale, presetSelection, fitType, garmentScaleHint, spec, }: BodyFirstFittingParams): BodyFirstFittingResult;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const BONE_VISIBILITY_MAP: Record<string, readonly number[]>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { NormalizedLandmark } from "@mediapipe/tasks-vision";
|
|
2
|
+
import * as THREE from "three";
|
|
3
|
+
interface StableShoulderWidthInput {
|
|
4
|
+
projectedShoulderWidth: number;
|
|
5
|
+
projectedTorsoHeight: number;
|
|
6
|
+
bodyYaw: number;
|
|
7
|
+
worldLandmarks?: NormalizedLandmark[] | null;
|
|
8
|
+
}
|
|
9
|
+
interface GarmentRootOrientationInput {
|
|
10
|
+
leftShoulder: THREE.Vector3;
|
|
11
|
+
rightShoulder: THREE.Vector3;
|
|
12
|
+
leftHip: THREE.Vector3;
|
|
13
|
+
rightHip: THREE.Vector3;
|
|
14
|
+
}
|
|
15
|
+
export declare function computeFacingAwareShoulderWidth(shoulderWidth: number, torsoHeight: number, bodyYaw: number): number;
|
|
16
|
+
export declare function computeStableShoulderWidth({ projectedShoulderWidth, projectedTorsoHeight, bodyYaw, worldLandmarks, }: StableShoulderWidthInput): number;
|
|
17
|
+
export declare function computeGarmentRootQuaternion({ leftShoulder, rightShoulder, leftHip, rightHip, }: GarmentRootOrientationInput, target?: THREE.Quaternion): THREE.Quaternion | null;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as THREE from "three";
|
|
2
|
+
export interface GarmentBoneBinding {
|
|
3
|
+
bone: THREE.Bone;
|
|
4
|
+
restQuaternion: THREE.Quaternion;
|
|
5
|
+
restScale: THREE.Vector3;
|
|
6
|
+
restWorldPosition?: THREE.Vector3;
|
|
7
|
+
restWorldQuaternion?: THREE.Quaternion;
|
|
8
|
+
restParentWorldQuaternion?: THREE.Quaternion;
|
|
9
|
+
}
|
|
10
|
+
export type GarmentBoneBindingMap = Map<string, GarmentBoneBinding[]>;
|
|
11
|
+
export interface GarmentFitProfile {
|
|
12
|
+
anchor: THREE.Vector3;
|
|
13
|
+
shoulderCenter: THREE.Vector3;
|
|
14
|
+
hipCenter: THREE.Vector3;
|
|
15
|
+
referenceWidth: number;
|
|
16
|
+
referenceTorsoHeight: number;
|
|
17
|
+
trackingHeight: number;
|
|
18
|
+
boundsCenter: THREE.Vector3;
|
|
19
|
+
boundsSize: THREE.Vector3;
|
|
20
|
+
hasBoneAnchors: boolean;
|
|
21
|
+
}
|
|
22
|
+
export declare function captureBoneBinding(bone: THREE.Bone): GarmentBoneBinding;
|
|
23
|
+
export declare function computeGarmentFitProfile(scene: THREE.Group, bones: GarmentBoneBindingMap, fallbackWidth?: number): GarmentFitProfile;
|
|
24
|
+
export declare function resetBoneRotations(bones: GarmentBoneBindingMap): void;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { NormalizedLandmark } from "@mediapipe/tasks-vision";
|
|
2
|
+
import { type MutableRefObject } from "react";
|
|
3
|
+
import * as THREE from "three";
|
|
4
|
+
import { type LandmarkCoordinateSpace } from "../pose/landmarkPoseSolver";
|
|
5
|
+
import { type GarmentBoneBindingMap } from "./garmentFitProfile";
|
|
6
|
+
export interface PoseApplicationRefs {
|
|
7
|
+
clockRef: MutableRefObject<THREE.Timer>;
|
|
8
|
+
prevRotationsRef: MutableRefObject<Map<string, THREE.Quaternion>>;
|
|
9
|
+
}
|
|
10
|
+
interface ApplyLandmarkPoseOptions {
|
|
11
|
+
coordinateSpace?: LandmarkCoordinateSpace;
|
|
12
|
+
excludeBones?: Set<string>;
|
|
13
|
+
}
|
|
14
|
+
export declare function usePoseApplicationRefs(): PoseApplicationRefs;
|
|
15
|
+
export declare function applyLandmarkPoseToGarment(landmarks: NormalizedLandmark[], bones: GarmentBoneBindingMap, refs: PoseApplicationRefs, options?: ApplyLandmarkPoseOptions): void;
|
|
16
|
+
export declare function resetPoseState(bones: GarmentBoneBindingMap, refs: PoseApplicationRefs): void;
|
|
17
|
+
export declare function blendBonesToRest(bones: GarmentBoneBindingMap, factor: number, delta: number, onlyBones?: Set<string>): void;
|
|
18
|
+
export {};
|