@zeewain/3d-avatar-sdk 1.2.0 → 1.2.2

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.
Files changed (55) hide show
  1. package/README.md +6 -5
  2. package/dist/assets/Build/webgl.data.unityweb +0 -0
  3. package/dist/assets/Build/webgl.framework.js.unityweb +0 -0
  4. package/dist/assets/Build/webgl.wasm.unityweb +0 -0
  5. package/dist/examples/test-umd/index.html +762 -0
  6. package/dist/examples/test-vue2/.eslintignore +45 -0
  7. package/dist/examples/test-vue2/.eslintrc.js +174 -0
  8. package/dist/examples/test-vue2/.stylelintignore +50 -0
  9. package/dist/examples/test-vue2/.stylelintrc.js +79 -0
  10. package/dist/examples/test-vue2/README.md +139 -0
  11. package/dist/examples/test-vue2/babel.config.js +14 -0
  12. package/dist/examples/test-vue2/package.json +53 -0
  13. package/dist/examples/test-vue2/pnpm-lock.yaml +8776 -0
  14. package/dist/examples/test-vue2/public/index.html +19 -0
  15. package/dist/examples/test-vue2/setup.js +170 -0
  16. package/dist/examples/test-vue2/src/App.vue +943 -0
  17. package/dist/examples/test-vue2/src/components/BroadcastAPI.vue +666 -0
  18. package/dist/examples/test-vue2/src/components/CameraAPI.vue +414 -0
  19. package/dist/examples/test-vue2/src/components/GlobalConfig.vue +200 -0
  20. package/dist/examples/test-vue2/src/components/InfoCards.vue +294 -0
  21. package/dist/examples/test-vue2/src/components/InitAPI.vue +334 -0
  22. package/dist/examples/test-vue2/src/components/LogPanel.vue +249 -0
  23. package/dist/examples/test-vue2/src/components/MotionControlAPI.vue +400 -0
  24. package/dist/examples/test-vue2/src/components/UnityPreview.vue +201 -0
  25. package/dist/examples/test-vue2/src/main.js +16 -0
  26. package/dist/examples/test-vue2/vue.config.js +41 -0
  27. package/dist/examples/test-vue3/.eslintrc +3 -0
  28. package/dist/examples/test-vue3/.stylelintignore +3 -0
  29. package/dist/examples/test-vue3/.stylelintrc +48 -0
  30. package/dist/examples/test-vue3/README.md +236 -0
  31. package/dist/examples/test-vue3/env.d.ts +8 -0
  32. package/dist/examples/test-vue3/index.html +95 -0
  33. package/dist/examples/test-vue3/package.json +55 -0
  34. package/dist/examples/test-vue3/pnpm-lock.yaml +4636 -0
  35. package/dist/examples/test-vue3/setup.js +167 -0
  36. package/dist/examples/test-vue3/src/App.vue +962 -0
  37. package/dist/examples/test-vue3/src/components/BroadcastAPI.vue +636 -0
  38. package/dist/examples/test-vue3/src/components/CameraAPI.vue +376 -0
  39. package/dist/examples/test-vue3/src/components/GlobalConfig.vue +213 -0
  40. package/dist/examples/test-vue3/src/components/InfoCards.vue +288 -0
  41. package/dist/examples/test-vue3/src/components/InitAPI.vue +339 -0
  42. package/dist/examples/test-vue3/src/components/LogPanel.vue +236 -0
  43. package/dist/examples/test-vue3/src/components/MotionControlAPI.vue +373 -0
  44. package/dist/examples/test-vue3/src/components/UnityPreview.vue +189 -0
  45. package/dist/examples/test-vue3/src/main.ts +12 -0
  46. package/dist/examples/test-vue3/src/types.ts +9 -0
  47. package/dist/examples/test-vue3/tsconfig.json +44 -0
  48. package/dist/examples/test-vue3/tsconfig.node.json +14 -0
  49. package/dist/examples/test-vue3/vite.config.ts +75 -0
  50. package/dist/index.d.ts +142 -132
  51. package/dist/index.es5.js +93 -41
  52. package/dist/index.es5.umd.js +93 -41
  53. package/dist/index.esm.js +101 -42
  54. package/dist/index.umd.cjs +101 -42
  55. package/package.json +4 -3
@@ -0,0 +1,376 @@
1
+ <template>
2
+ <div class="camera-api">
3
+ <div class="api-description">
4
+ <el-alert
5
+ title="API说明"
6
+ type="info"
7
+ :closable="false"
8
+ show-icon
9
+ >
10
+ <template template #default>
11
+ <div class="api-signature">
12
+ <code>setCamera(type: AvatarCameraType): Promise&lt;IAvatarCallbackResponse&gt;</code>
13
+ </div>
14
+ <p>设置数字人的摄像机类型和视角,支持全身、半身、近景三种预设类型</p>
15
+ <p class="api-features">
16
+ ✅ 实时镜头切换 &nbsp;&nbsp;
17
+ ✅ 平滑过渡动画 &nbsp;&nbsp;
18
+ ✅ 多种预设视角
19
+ </p>
20
+ </template>
21
+ </el-alert>
22
+ </div>
23
+
24
+ <div class="api-controls">
25
+ <el-card shadow="hover" class="control-card">
26
+ <template #header>
27
+ <div class="card-header">
28
+ <span>镜头控制</span>
29
+ <el-tag v-if="sdkStatus.canControlCamera" type="success" size="default">可用</el-tag>
30
+ <el-tag v-else type="info" size="default">不可用</el-tag>
31
+ </div>
32
+ </template>
33
+ <div class="control-content">
34
+ <div class="preset-selector">
35
+ <el-form :model="presetData" label-width="80px" size="default">
36
+ <el-form-item label="预设视角" required>
37
+ <el-radio-group v-model="presetData.preset" class="preset-radio-group">
38
+ <el-radio-button value="whole">
39
+ <i class="el-icon-full-screen"></i>
40
+ 全身
41
+ </el-radio-button>
42
+ <el-radio-button value="half">
43
+ <i class="el-icon-picture"></i>
44
+ 半身
45
+ </el-radio-button>
46
+ <el-radio-button value="face">
47
+ <i class="el-icon-view"></i>
48
+ 近景
49
+ </el-radio-button>
50
+ </el-radio-group>
51
+ </el-form-item>
52
+
53
+ <el-form-item label="预览">
54
+ <div class="preset-preview">
55
+ <div class="preview-card" :class="{ active: presetData.preset === 'whole' }">
56
+ <div class="preview-icon">👤</div>
57
+ <div class="preview-label">全身视角</div>
58
+ <div class="preview-desc">显示数字人全身</div>
59
+ </div>
60
+ <div class="preview-card" :class="{ active: presetData.preset === 'half' }">
61
+ <div class="preview-icon">🧑‍💼</div>
62
+ <div class="preview-label">半身视角</div>
63
+ <div class="preview-desc">显示数字人上半身</div>
64
+ </div>
65
+ <div class="preview-card" :class="{ active: presetData.preset === 'face' }">
66
+ <div class="preview-icon">😊</div>
67
+ <div class="preview-label">近景视角</div>
68
+ <div class="preview-desc">显示数字人面部特写</div>
69
+ </div>
70
+ </div>
71
+ </el-form-item>
72
+
73
+ <el-form-item class="action-buttons">
74
+ <el-button
75
+ type="primary"
76
+ icon="camera"
77
+ :loading="isLoading"
78
+ :disabled="!sdkStatus.canControlCamera || !presetData.preset || !globalConfig.avatarCode"
79
+ @click="handleSetCameraPreset"
80
+ >
81
+ {{ isLoading ? '切换中...' : '应用镜头设置' }}
82
+ </el-button>
83
+ </el-form-item>
84
+ </el-form>
85
+ </div>
86
+
87
+ <div class="status-tips">
88
+ <el-alert
89
+ v-if="!sdkStatus.canControlCamera"
90
+ title="请先初始化Avatar后再进行镜头控制"
91
+ type="warning"
92
+ :closable="false"
93
+ show-icon
94
+ />
95
+ <el-alert
96
+ v-else-if="!globalConfig.avatarCode"
97
+ title="请先在全局配置中设置Avatar Code"
98
+ type="warning"
99
+ :closable="false"
100
+ show-icon
101
+ />
102
+ </div>
103
+ </div>
104
+ </el-card>
105
+ </div>
106
+
107
+ <div class="api-result">
108
+ <el-card shadow="hover" class="result-card">
109
+ <template #header>
110
+ <div class="card-header">
111
+ <span>执行结果</span>
112
+ <el-link
113
+ size="default"
114
+ icon="refresh"
115
+ @click="clearResult"
116
+ >
117
+ 清空
118
+ </el-link>
119
+ </div>
120
+ </template>
121
+ <div class="result-content">
122
+ <pre class="result-text">{{ result }}</pre>
123
+ </div>
124
+ </el-card>
125
+ </div>
126
+ </div>
127
+ </template>
128
+
129
+ <script setup lang="ts">
130
+ import { ref, reactive } from 'vue';
131
+ import { ElMessage } from 'element-plus';
132
+
133
+ interface ISDKStatus {
134
+ canControlCamera: boolean;
135
+ }
136
+ interface IGlobalConfig {
137
+ avatarCode: string;
138
+ }
139
+
140
+ const props = defineProps<{
141
+ sdkStatus: ISDKStatus;
142
+ globalConfig: IGlobalConfig;
143
+ }>();
144
+ const emit = defineEmits<{
145
+ (e: 'set-camera-preset', params: { preset: string }): void;
146
+ }>();
147
+
148
+ const presetData = reactive({
149
+ preset: 'whole',
150
+ });
151
+ const result = ref(
152
+ '等待镜头控制操作...\n\n支持的镜头类型:\n- whole: 全身视角,展示数字人完整形象\n- half: 半身视角,适合对话场景\n- face: 近景视角,突出面部表情'
153
+ );
154
+ const isLoading = ref(false);
155
+
156
+ function getPresetName(preset: string) {
157
+ const names: Record<string, string> = {
158
+ whole: '全身视角',
159
+ half: '半身视角',
160
+ face: '近景视角',
161
+ };
162
+ return names[preset] || preset;
163
+ }
164
+
165
+ function clearResult() {
166
+ result.value = '等待镜头控制操作...\n\n支持的镜头类型:\n- whole: 全身视角,展示数字人完整形象\n- half: 半身视角,适合对话场景\n- face: 近景视角,突出面部表情';
167
+ }
168
+
169
+ function handleSetCameraPreset() {
170
+ const { avatarCode } = props.globalConfig;
171
+ if (!avatarCode) {
172
+ result.value = '❌ 请先在全局配置中设置Avatar Code';
173
+ ElMessage.warning('请先设置Avatar Code');
174
+ return;
175
+ }
176
+ if (!presetData.preset) {
177
+ result.value = '❌ 请选择镜头预设类型';
178
+ ElMessage.warning('请选择镜头预设类型');
179
+ return;
180
+ }
181
+ isLoading.value = true;
182
+ const presetName = getPresetName(presetData.preset);
183
+ result.value = `🔄 正在设置镜头...\n📹 目标视角: ${presetName}\n⚙️ 类型: ${presetData.preset}\n\n📡 发送镜头切换指令...`;
184
+ try {
185
+ emit('set-camera-preset', { preset: presetData.preset });
186
+ setTimeout(() => {
187
+ isLoading.value = false;
188
+ result.value = `✅ 镜头设置请求已发送\n📋 请查看右侧日志面板获取详细信息\n\n📝 操作说明:\n- 镜头将平滑切换到${presetName}\n- 切换过程可能需要几秒钟\n- 不同视角适合不同的应用场景`;
189
+ }, 800);
190
+ } catch (error: any) {
191
+ isLoading.value = false;
192
+ result.value = `❌ 镜头设置失败: ${error.message}\n\n🔍 可能的原因:\n- Avatar未正确初始化\n- 镜头类型不支持\n- Unity通信异常`;
193
+ ElMessage.error(`镜头设置失败: ${error.message}`);
194
+ }
195
+ }
196
+ </script>
197
+
198
+ <style lang="scss" scoped>
199
+ .camera-api {
200
+ .api-description {
201
+ margin-bottom: 20px;
202
+ .api-signature {
203
+ background-color: #f5f5f5;
204
+ padding: 8px 12px;
205
+ border-radius: 4px;
206
+ margin-bottom: 10px;
207
+ font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
208
+ font-size: 12px;
209
+ border-left: 4px solid #e6a23c;
210
+ code {
211
+ color: #2c3e50;
212
+ font-weight: 600;
213
+ }
214
+ }
215
+ p {
216
+ margin: 5px 0;
217
+ color: #606266;
218
+ font-size: 14px;
219
+ &.api-features {
220
+ color: #e6a23c;
221
+ font-weight: 500;
222
+ margin-top: 8px;
223
+ }
224
+ }
225
+ }
226
+ .api-controls {
227
+ margin-bottom: 20px;
228
+ .control-card {
229
+ .card-header {
230
+ display: flex;
231
+ justify-content: space-between;
232
+ align-items: center;
233
+ font-weight: 600;
234
+ }
235
+ .control-content {
236
+ .preset-selector {
237
+ .el-form-item {
238
+ margin-bottom: 18px;
239
+ :deep(.el-form-item__label) {
240
+ font-weight: 500;
241
+ color: #303133;
242
+ }
243
+ &.action-buttons {
244
+ margin-bottom: 0;
245
+ margin-top: 25px;
246
+ .el-button {
247
+ width: 100%;
248
+ padding: 10px 0;
249
+ font-weight: 500;
250
+ }
251
+ }
252
+ }
253
+ .preset-radio-group {
254
+ width: 100%;
255
+ .el-radio-button {
256
+ flex: 1;
257
+ :deep(.el-radio-button__inner) {
258
+ width: 100%;
259
+ padding: 8px 15px;
260
+ i {
261
+ margin-right: 5px;
262
+ }
263
+ }
264
+ }
265
+ }
266
+ .preset-preview {
267
+ display: flex;
268
+ gap: 10px;
269
+ margin-top: 10px;
270
+ .preview-card {
271
+ flex: 1;
272
+ padding: 12px;
273
+ border: 2px solid #e4e7ed;
274
+ border-radius: 6px;
275
+ text-align: center;
276
+ cursor: pointer;
277
+ transition: all 0.3s;
278
+ &:hover {
279
+ border-color: #409eff;
280
+ background-color: #f0f9ff;
281
+ }
282
+ &.active {
283
+ border-color: #409eff;
284
+ background-color: #ecf5ff;
285
+ }
286
+ .preview-icon {
287
+ font-size: 24px;
288
+ margin-bottom: 8px;
289
+ }
290
+ .preview-label {
291
+ font-weight: 500;
292
+ color: #303133;
293
+ margin-bottom: 4px;
294
+ font-size: 13px;
295
+ }
296
+ .preview-desc {
297
+ color: #909399;
298
+ font-size: 11px;
299
+ line-height: 1.3;
300
+ }
301
+ }
302
+ }
303
+ }
304
+ .status-tips {
305
+ margin-top: 15px;
306
+ .el-alert {
307
+ margin-bottom: 10px;
308
+ &:last-child {
309
+ margin-bottom: 0;
310
+ }
311
+ }
312
+ }
313
+ }
314
+ }
315
+ }
316
+ .api-result {
317
+ .result-card {
318
+ .card-header {
319
+ display: flex;
320
+ justify-content: space-between;
321
+ align-items: center;
322
+ font-weight: 600;
323
+ }
324
+ .result-content {
325
+ max-height: 300px;
326
+ overflow-y: auto;
327
+ .result-text {
328
+ margin: 0;
329
+ padding: 15px;
330
+ background-color: #f8f9fa;
331
+ border-radius: 4px;
332
+ border: 1px solid #e9ecef;
333
+ font-family: Monaco, Menlo, "Ubuntu Mono", monospace;
334
+ font-size: 13px;
335
+ line-height: 1.6;
336
+ color: #2c3e50;
337
+ white-space: pre-wrap;
338
+ word-wrap: break-word;
339
+ }
340
+ }
341
+ }
342
+ }
343
+ }
344
+
345
+ // 移动端优化
346
+ @media screen and (width <= 768px) {
347
+ .camera-api {
348
+ .preset-radio-group {
349
+ .el-radio-button {
350
+ :deep(.el-radio-button__inner) {
351
+ padding: 6px 10px;
352
+ font-size: 12px;
353
+ i {
354
+ margin-right: 3px;
355
+ }
356
+ }
357
+ }
358
+ }
359
+ .preset-preview {
360
+ .preview-card {
361
+ padding: 8px;
362
+ .preview-icon {
363
+ font-size: 20px;
364
+ margin-bottom: 6px;
365
+ }
366
+ .preview-label {
367
+ font-size: 12px;
368
+ }
369
+ .preview-desc {
370
+ font-size: 10px;
371
+ }
372
+ }
373
+ }
374
+ }
375
+ }
376
+ </style>
@@ -0,0 +1,213 @@
1
+ <template>
2
+ <div class="global-config">
3
+ <div class="config-header">
4
+ <el-icon :size="18">
5
+ <Setting />
6
+ </el-icon>
7
+ <span class="config-title">全局配置</span>
8
+ <el-tag type="primary" size="default">必填</el-tag>
9
+ </div>
10
+
11
+ <el-form :model="modelValue" size="default" label-width="120px" :inline="true" label-position="top" class="config-form">
12
+ <el-form-item label="调试环境" required>
13
+ <el-radio-group v-model="modelValue.env">
14
+ <el-radio-button value="dev">开发</el-radio-button>
15
+ <el-radio-button value="test">测试</el-radio-button>
16
+ <el-radio-button value="prod">生产</el-radio-button>
17
+ <el-radio-button value="custom">自定义</el-radio-button>
18
+ </el-radio-group>
19
+ </el-form-item>
20
+ <el-form-item v-if="modelValue.env === 'custom'" label="API地址" required>
21
+ <el-input
22
+ v-model="modelValue.apiBaseUrl"
23
+ placeholder="请输入API地址"
24
+ clearable>
25
+ <template #prefix>
26
+ <el-icon><Folder /></el-icon>
27
+ </template>
28
+ </el-input>
29
+ </el-form-item>
30
+ <el-form-item v-if="modelValue.env === 'custom'" label="AB包地址">
31
+ <el-input
32
+ v-model="modelValue.resourcesUrl"
33
+ placeholder="请输入AB包地址"
34
+ clearable>
35
+ </el-input>
36
+ </el-form-item>
37
+ <el-form-item label="WebGL路径" required>
38
+ <el-input
39
+ v-model="modelValue.webglPath"
40
+ placeholder="请输入WebGL路径"
41
+ clearable>
42
+ <template #prefix>
43
+ <el-icon><Folder /></el-icon>
44
+ </template>
45
+ </el-input>
46
+ </el-form-item>
47
+ <el-form-item label="Token" required>
48
+ <el-input
49
+ v-model="modelValue.token"
50
+ placeholder="请输入全局Token"
51
+ clearable
52
+ >
53
+ <template #prefix>
54
+ <el-icon><Key /></el-icon>
55
+ </template>
56
+ </el-input>
57
+ </el-form-item>
58
+
59
+ <el-form-item label="Avatar Code" required>
60
+ <el-input
61
+ v-model="modelValue.avatarCode"
62
+ placeholder="请输入数字人编码"
63
+ clearable
64
+ >
65
+ <template #prefix>
66
+ <el-icon><User /></el-icon>
67
+ </template>
68
+ </el-input>
69
+ </el-form-item>
70
+ <el-form-item label="待机动作列表">
71
+ <div style="display: flex; flex-direction: column;">
72
+ <el-input
73
+ v-model="modelValue.idleMotionListString"
74
+ placeholder="请输入待机动作列表"
75
+ clearable
76
+ >
77
+ </el-input>
78
+ <div style="font-size: 12px; color: #999;">
79
+ 动作编码列表,多个动作编码用逗号分隔
80
+ </div>
81
+ </div>
82
+ </el-form-item>
83
+ <div class="config-actions">
84
+ <el-button
85
+ type="primary"
86
+ size="default"
87
+ @click="saveConfig"
88
+ :disabled="!modelValue.token || !modelValue.avatarCode"
89
+ >
90
+ <template #icon>
91
+ <el-icon><Check /></el-icon>
92
+ </template>
93
+ 保存配置
94
+ </el-button>
95
+ </div>
96
+ </el-form>
97
+
98
+ <div class="config-tips">
99
+ <el-alert
100
+ title="配置提示"
101
+ type="info"
102
+ :closable="false"
103
+ show-icon
104
+ >
105
+ <template #default>
106
+ <ul>
107
+ <li>1、Token: 用于API鉴权的访问令牌。 2、Avatar Code: 默认数字人编码,用于初始化Avatar。 3、配置保存后将自动应用到所有API接口</li>
108
+ </ul>
109
+ </template>
110
+ </el-alert>
111
+ </div>
112
+ </div>
113
+ </template>
114
+
115
+ <script setup lang="ts">
116
+ import { ElMessage } from 'element-plus';
117
+ import { Setting, Key, User, Check, Folder } from '@element-plus/icons-vue';
118
+ import type { IGlobalConfig } from '../types';
119
+
120
+ // 定义 props
121
+ const props = defineProps<{
122
+ modelValue: IGlobalConfig;
123
+ }>();
124
+
125
+ const modelValue = defineModel<IGlobalConfig>({
126
+ required: true
127
+ });
128
+
129
+ // 定义 emits
130
+ const emit = defineEmits<{
131
+ 'save-config': [];
132
+ 'apply-all': [];
133
+ }>();
134
+
135
+
136
+ // 保存配置
137
+ function saveConfig(): void {
138
+ if (!modelValue.value.token || !modelValue.value.avatarCode) {
139
+ ElMessage.warning('请填写完整的配置信息');
140
+ return;
141
+ }
142
+
143
+ emit('save-config');
144
+ }
145
+
146
+ </script>
147
+
148
+ <style lang="scss" scoped>
149
+ .global-config {
150
+ display: flex;
151
+ flex-direction: column;
152
+ justify-content: center;
153
+ gap: 20px;
154
+ .config-header {
155
+ display: flex;
156
+ align-items: center;
157
+ gap: 10px;
158
+ margin-bottom: 20px;
159
+ padding: 10px;
160
+ background: linear-gradient(135deg, #409eff, #66b1ff);
161
+ color: white;
162
+ border-radius: 4px;
163
+ .config-title {
164
+ font-weight: 600;
165
+ font-size: 14px;
166
+ }
167
+ }
168
+ .config-form {
169
+ :deep(.el-form-item) {
170
+ .el-input {
171
+ width: 300px;
172
+ }
173
+ }
174
+ }
175
+ .config-actions {
176
+ display: flex;
177
+ align-items: center;
178
+ }
179
+ .config-tips {
180
+ :deep(.el-alert__content) {
181
+ ul {
182
+ margin: 0;
183
+ li {
184
+ margin: 5px 0;
185
+ font-size: 12px;
186
+ line-height: 1.5;
187
+ }
188
+ }
189
+ }
190
+ }
191
+ }
192
+
193
+ // 移动端优化
194
+ @media screen and (max-width: 768px) {
195
+ .global-config {
196
+ .config-form {
197
+ :deep(.el-form-item) {
198
+ .el-form-item__label {
199
+ width: 80px !important;
200
+ font-size: 12px;
201
+ }
202
+ }
203
+ .config-actions {
204
+ .el-button {
205
+ display: block;
206
+ width: 100%;
207
+ margin: 5px 0;
208
+ }
209
+ }
210
+ }
211
+ }
212
+ }
213
+ </style>