@spatialwalk/avatarkit 1.0.0-beta.7 → 1.0.0-beta.71

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 (101) hide show
  1. package/CHANGELOG.md +602 -10
  2. package/README.md +475 -312
  3. package/dist/StreamingAudioPlayer-D8Q8WiEg.js +638 -0
  4. package/dist/animation/AnimationWebSocketClient.d.ts +6 -50
  5. package/dist/animation/utils/eventEmitter.d.ts +1 -9
  6. package/dist/animation/utils/flameConverter.d.ts +3 -24
  7. package/dist/audio/AnimationPlayer.d.ts +6 -57
  8. package/dist/audio/StreamingAudioPlayer.d.ts +2 -118
  9. package/dist/avatar_core_wasm-Dv943JJl.js +2696 -0
  10. package/dist/{avatar_core_wasm.wasm → avatar_core_wasm-e68766db.wasm} +0 -0
  11. package/dist/config/app-config.d.ts +3 -4
  12. package/dist/config/constants.d.ts +10 -18
  13. package/dist/config/sdk-config-loader.d.ts +4 -10
  14. package/dist/core/Avatar.d.ts +2 -14
  15. package/dist/core/AvatarController.d.ts +95 -85
  16. package/dist/core/AvatarDownloader.d.ts +7 -92
  17. package/dist/core/AvatarManager.d.ts +22 -12
  18. package/dist/core/AvatarSDK.d.ts +35 -0
  19. package/dist/core/AvatarView.d.ts +55 -140
  20. package/dist/core/NetworkLayer.d.ts +7 -59
  21. package/dist/generated/common/v1/models.d.ts +36 -0
  22. package/dist/generated/driveningress/v1/driveningress.d.ts +0 -1
  23. package/dist/generated/driveningress/v2/driveningress.d.ts +82 -1
  24. package/dist/generated/google/protobuf/struct.d.ts +0 -1
  25. package/dist/generated/google/protobuf/timestamp.d.ts +0 -1
  26. package/dist/index-U8QcNdma.js +16477 -0
  27. package/dist/index.d.ts +2 -4
  28. package/dist/index.js +17 -18
  29. package/dist/renderer/RenderSystem.d.ts +9 -79
  30. package/dist/renderer/covariance.d.ts +3 -11
  31. package/dist/renderer/renderer.d.ts +6 -2
  32. package/dist/renderer/sortSplats.d.ts +3 -10
  33. package/dist/renderer/webgl/reorderData.d.ts +4 -11
  34. package/dist/renderer/webgl/webglRenderer.d.ts +34 -4
  35. package/dist/renderer/webgpu/webgpuRenderer.d.ts +30 -5
  36. package/dist/types/character-settings.d.ts +1 -1
  37. package/dist/types/character.d.ts +3 -15
  38. package/dist/types/index.d.ts +123 -43
  39. package/dist/utils/animation-interpolation.d.ts +4 -15
  40. package/dist/utils/client-id.d.ts +6 -0
  41. package/dist/utils/conversationId.d.ts +10 -0
  42. package/dist/utils/error-utils.d.ts +0 -1
  43. package/dist/utils/id-manager.d.ts +34 -0
  44. package/dist/utils/logger.d.ts +2 -11
  45. package/dist/utils/posthog-tracker.d.ts +8 -0
  46. package/dist/utils/pwa-cache-manager.d.ts +17 -0
  47. package/dist/utils/usage-tracker.d.ts +6 -0
  48. package/dist/vanilla/vite.config.d.ts +2 -0
  49. package/dist/vite.d.ts +19 -0
  50. package/dist/wasm/avatarCoreAdapter.d.ts +15 -126
  51. package/dist/wasm/avatarCoreMemory.d.ts +5 -2
  52. package/package.json +19 -8
  53. package/vite.d.ts +20 -0
  54. package/vite.js +126 -0
  55. package/dist/StreamingAudioPlayer-D7s8q5h0.js +0 -319
  56. package/dist/StreamingAudioPlayer-D7s8q5h0.js.map +0 -1
  57. package/dist/animation/AnimationWebSocketClient.d.ts.map +0 -1
  58. package/dist/animation/utils/eventEmitter.d.ts.map +0 -1
  59. package/dist/animation/utils/flameConverter.d.ts.map +0 -1
  60. package/dist/audio/AnimationPlayer.d.ts.map +0 -1
  61. package/dist/audio/StreamingAudioPlayer.d.ts.map +0 -1
  62. package/dist/avatar_core_wasm-D4eEi7Eh.js +0 -1666
  63. package/dist/avatar_core_wasm-D4eEi7Eh.js.map +0 -1
  64. package/dist/config/app-config.d.ts.map +0 -1
  65. package/dist/config/constants.d.ts.map +0 -1
  66. package/dist/config/sdk-config-loader.d.ts.map +0 -1
  67. package/dist/core/Avatar.d.ts.map +0 -1
  68. package/dist/core/AvatarController.d.ts.map +0 -1
  69. package/dist/core/AvatarDownloader.d.ts.map +0 -1
  70. package/dist/core/AvatarKit.d.ts +0 -66
  71. package/dist/core/AvatarKit.d.ts.map +0 -1
  72. package/dist/core/AvatarManager.d.ts.map +0 -1
  73. package/dist/core/AvatarView.d.ts.map +0 -1
  74. package/dist/core/NetworkLayer.d.ts.map +0 -1
  75. package/dist/generated/driveningress/v1/driveningress.d.ts.map +0 -1
  76. package/dist/generated/driveningress/v2/driveningress.d.ts.map +0 -1
  77. package/dist/generated/google/protobuf/struct.d.ts.map +0 -1
  78. package/dist/generated/google/protobuf/timestamp.d.ts.map +0 -1
  79. package/dist/index-CpSvWi6A.js +0 -6026
  80. package/dist/index-CpSvWi6A.js.map +0 -1
  81. package/dist/index.d.ts.map +0 -1
  82. package/dist/index.js.map +0 -1
  83. package/dist/renderer/RenderSystem.d.ts.map +0 -1
  84. package/dist/renderer/covariance.d.ts.map +0 -1
  85. package/dist/renderer/renderer.d.ts.map +0 -1
  86. package/dist/renderer/sortSplats.d.ts.map +0 -1
  87. package/dist/renderer/webgl/reorderData.d.ts.map +0 -1
  88. package/dist/renderer/webgl/webglRenderer.d.ts.map +0 -1
  89. package/dist/renderer/webgpu/webgpuRenderer.d.ts.map +0 -1
  90. package/dist/types/character-settings.d.ts.map +0 -1
  91. package/dist/types/character.d.ts.map +0 -1
  92. package/dist/types/index.d.ts.map +0 -1
  93. package/dist/utils/animation-interpolation.d.ts.map +0 -1
  94. package/dist/utils/cls-tracker.d.ts +0 -17
  95. package/dist/utils/cls-tracker.d.ts.map +0 -1
  96. package/dist/utils/error-utils.d.ts.map +0 -1
  97. package/dist/utils/logger.d.ts.map +0 -1
  98. package/dist/utils/reqId.d.ts +0 -20
  99. package/dist/utils/reqId.d.ts.map +0 -1
  100. package/dist/wasm/avatarCoreAdapter.d.ts.map +0 -1
  101. package/dist/wasm/avatarCoreMemory.d.ts.map +0 -1
@@ -0,0 +1,34 @@
1
+ /**
2
+ * ID Manager
3
+ * Unified management of all types of IDs in SDK
4
+ * @internal
5
+ */
6
+ /**
7
+ * ID type definitions
8
+ */
9
+ export interface SdkIds {
10
+ clientId: string;
11
+ userId: string | null;
12
+ appId: string | null;
13
+ sessionToken: string | null;
14
+ connectionId: string | null;
15
+ conversationId: string | null;
16
+ }
17
+ declare class IdManager {
18
+ private ids;
19
+ constructor();
20
+ getClientId(): string;
21
+ setUserId(userId: string | null): void;
22
+ getUserId(): string | null;
23
+ setAppId(appId: string | null): void;
24
+ getAppId(): string | null;
25
+ setSessionToken(token: string | null): void;
26
+ getSessionToken(): string | null;
27
+ getConnectionId(): string | null;
28
+ clearConnectionId(): void;
29
+ getConversationId(): string | null;
30
+ setConversationId(conversationId: string | null): void;
31
+ clearConversationId(): void;
32
+ }
33
+ export declare const idManager: IdManager;
34
+ export {};
@@ -1,12 +1,4 @@
1
- /**
2
- * Logger Utility
3
- * Environment-aware logger wrapper
4
- * - Logs normally in test/dev environment
5
- * - In production: silently logs to console
6
- * - Errors and warnings are always reported to CLS (when enabled)
7
- *
8
- * Usage: Replace `console.log()` with `logger.log()`
9
- */
1
+ import { LogLevel as GuiiaiLogLevel } from '@guiiai/logg';
10
2
  export declare const logger: import('@guiiai/logg').Logg;
11
3
  export declare const loggerWithUnknown: {
12
4
  error: (message: string, error?: unknown) => void;
@@ -14,7 +6,7 @@ export declare const loggerWithUnknown: {
14
6
  useGlobalConfig: () => import('@guiiai/logg').Logg;
15
7
  child: (fields?: Record<string, any>) => import('@guiiai/logg').Logg;
16
8
  withContext: (context: string) => import('@guiiai/logg').Logg;
17
- withLogLevel: (logLevel: import('@guiiai/logg').LogLevel) => import('@guiiai/logg').Logg;
9
+ withLogLevel: (logLevel: GuiiaiLogLevel) => import('@guiiai/logg').Logg;
18
10
  withLogLevelString: (logLevelString: import('@guiiai/logg').LogLevelString) => import('@guiiai/logg').Logg;
19
11
  withFormat: (format: import('@guiiai/logg').Format) => import('@guiiai/logg').Logg;
20
12
  withFields: (fields: Record<string, any>) => import('@guiiai/logg').Logg;
@@ -32,4 +24,3 @@ export declare const loggerWithUnknown: {
32
24
  withTimeFormatter: (fn: (inputDate: Date) => string) => import('@guiiai/logg').Logg;
33
25
  withErrorProcessor: (fn: (err: Error | unknown) => Error | unknown) => import('@guiiai/logg').Logg;
34
26
  };
35
- //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1,8 @@
1
+ /**
2
+ * PostHog Telemetry Tool (Browser Version)
3
+ *
4
+ * Unified PostHog telemetry reporting, supports custom reporting
5
+ * Uses PostHog JS SDK for event tracking, suitable for browser environments
6
+ * @internal
7
+ */
8
+ export {};
@@ -0,0 +1,17 @@
1
+ /**
2
+ * PWA Cache Manager
3
+ * Manages Service Worker Cache for character resources and template resources
4
+ * @internal
5
+ */
6
+ /**
7
+ * PWA Cache Manager
8
+ * Manages character resources cache (per character) and template resources cache (versioned)
9
+ */
10
+ export declare class PwaCacheManager {
11
+ private static readonly TEMPLATE_RESOURCE_VERSION;
12
+ private static readonly TEMPLATE_CACHE_NAME;
13
+ private static readonly TEMPLATE_VERSION_STORAGE_KEY;
14
+ private static readonly CHARACTER_CACHE_PREFIX;
15
+ private static readonly CHARACTER_CACHE_SUFFIX;
16
+ private static readonly MAX_CHARACTER_CACHE_ENTRIES;
17
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Usage tracking utility
3
+ * Used to determine first use, daily active status, etc.
4
+ * @internal
5
+ */
6
+ export {};
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
package/dist/vite.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import { Plugin } from 'vite';
2
+ /**
3
+ * Vite plugin for @spatialwalk/avatarkit
4
+ * Automatically handles WASM file configuration for development and production builds
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { defineConfig } from 'vite'
9
+ * import { avatarkitVitePlugin } from '@spatialwalk/avatarkit/vite'
10
+ *
11
+ * export default defineConfig({
12
+ * plugins: [
13
+ * avatarkitVitePlugin()
14
+ * ]
15
+ * })
16
+ * ```
17
+ */
18
+ export declare function avatarkitVitePlugin(): Plugin;
19
+ export default avatarkitVitePlugin;
@@ -1,4 +1,10 @@
1
- import { AvatarCoreMemoryManager } from './avatarCoreMemory';
1
+ /**
2
+ * Avatar Core WASM Adapter
3
+ *
4
+ * Completely replaces FlameComplete3DGSManager, provides full functionality of avatar_core_wasm
5
+ * Includes advanced features such as teeth subdivision, eye tracking, etc.
6
+ * @internal
7
+ */
2
8
  export interface WasmModuleConfig {
3
9
  baseUrl?: string;
4
10
  [key: string]: unknown;
@@ -13,13 +19,6 @@ export interface AvatarCoreOptions {
13
19
  wasmConfig?: WasmModuleConfig;
14
20
  wasmPath?: string;
15
21
  }
16
- interface PerformanceMetrics {
17
- initTime: number;
18
- loadTime: number;
19
- computeFrames: number;
20
- totalComputeTime: number;
21
- averageComputeTime: number;
22
- }
23
22
  export interface FlameInfo {
24
23
  vertexCount: number;
25
24
  faceCount: number;
@@ -46,6 +45,8 @@ export declare class AvatarCoreAdapter {
46
45
  private wasmModule;
47
46
  private memoryManager;
48
47
  private coreHandle;
48
+ private characterHandles;
49
+ private animationHandles;
49
50
  private characterHandle;
50
51
  private animationHandle;
51
52
  private totalFrames;
@@ -58,131 +59,19 @@ export declare class AvatarCoreAdapter {
58
59
  private flameInfo?;
59
60
  private characterInfo?;
60
61
  constructor(options?: AvatarCoreOptions);
61
- /**
62
- * 加载 WASM 模块并设置 API
63
- * 每次都创建全新的 WASM 实例,确保 C++ 内存是干净的
64
- *
65
- * 注意:这里使用动态 import() 导入 WASM 模块。
66
- * Vite 在构建时会自动为 WASM 文件和 JS glue 代码添加 hash(如 avatar_core_wasm-CxWuw7eS.wasm),
67
- * 确保浏览器缓存与版本一致,不会有缓存问题。
68
- *
69
- * Hash 的作用机制:
70
- * - WASM 文件内容变化 → hash 自动变化 → URL 变化 → 浏览器拉取新版本
71
- * - WASM 文件内容不变 → hash 保持不变 → URL 不变 → 浏览器使用缓存
72
- * - Emscripten 生成的 JS 内部会使用 hard-coded 的 hash 路径加载 .wasm 文件
73
- */
74
- loadWASMModule(): Promise<void>;
75
- /**
76
- * 验证 WASM 模块功能
77
- */
78
- private validateWASMModule;
79
- /**
80
- * 初始化内存视图
81
- */
82
- private initializeMemoryViews;
83
- /**
84
- * 设置 C API 函数包装
85
- */
86
- private setupCAPIFunctions;
87
- /**
88
- * 读取当前动画帧的 FlameParams(用于过渡或调试)
89
- */
90
- getCurrentFrameParams(frameIndex?: number): Promise<FlameParams>;
91
- /**
92
- * 初始化 Avatar Core 核心
93
- */
94
- private initializeAvatarCore;
95
- /**
96
- * 加载模板资源(从预加载的 ArrayBuffers)
97
- */
98
- loadTemplateResourcesFromBuffers(templateResources: Record<string, ArrayBuffer>): Promise<boolean>;
99
- /**
100
- * 加载角色数据(从预加载的 ArrayBuffers)
101
- */
102
- loadCharacterFromBuffers(shapeBuffer: ArrayBuffer, pointCloudBuffer: ArrayBuffer): Promise<boolean>;
103
62
  private loadAnimationFromData;
104
63
  /**
105
64
  * Load animation from ArrayBuffer (for CDN-based dynamic loading)
65
+ * @param animData Animation data buffer
66
+ * @param characterId Optional character ID for multi-character support
67
+ * @returns Animation handle
106
68
  */
107
- loadAnimationFromBuffer(animData: ArrayBuffer): Promise<number>;
69
+ loadAnimationFromBuffer(animData: ArrayBuffer, characterId?: string): Promise<number>;
108
70
  switchAnimationFile(animationFile: string): Promise<number>;
109
71
  /**
110
- * 获取动画总帧数
111
- */
112
- getAnimationTotalFrames(): Promise<number>;
113
- /**
114
- * 从动画中获取指定帧的参数
115
- */
116
- getAnimationFrameParams(frameIndex?: number): Promise<number>;
117
- /**
118
- * 设置眼部追踪配置(对齐 app 实现)
119
- */
120
- setEyeTrackingConfig(config: {
121
- enabled: boolean;
122
- auto_eyelid_adjustment?: boolean;
123
- eyelid_threshold?: number;
124
- }): Promise<boolean>;
125
- /**
126
- * 设置眼部追踪目标(高级功能)
127
- */
128
- setGazeTarget(x: number, y: number, z: number): Promise<boolean>;
129
- /**
130
- * 重置眼部追踪
131
- */
132
- resetEyeTracking(): Promise<boolean>;
133
- /**
134
- * 查询 FLAME 模型信息
135
- */
136
- private queryFlameInfo;
137
- /**
138
- * 查询角色信息
139
- */
140
- private queryCharacterInfo;
141
- /**
142
- * 检查错误码并抛出异常
143
- */
144
- private checkError;
145
- /**
146
- * 更新进度回调
147
- */
148
- private updateProgress;
149
- /**
150
- * 获取性能指标
151
- */
152
- getPerformanceMetrics(): PerformanceMetrics & {
153
- memoryStats?: ReturnType<AvatarCoreMemoryManager['getMemoryStats']>;
154
- flameInfo?: FlameInfo;
155
- characterInfo?: CharacterInfo;
156
- version?: string;
157
- };
158
- /**
159
- * 释放当前角色和动画资源(但保留 core)
72
+ * Release current character (legacy method, kept for backward compatibility)
73
+ * @deprecated Use removeCharacter() instead for multi-character support
160
74
  */
161
75
  releaseCurrentCharacter(): void;
162
- /**
163
- * 释放所有资源(包括 core)
164
- */
165
- release(): void;
166
- /**
167
- * 兼容性接口:提供与 FlameComplete3DGSManager 相同的接口
168
- */
169
- loadFlameModel(_modelData: any): Promise<boolean>;
170
76
  load3DGSData(_original3DGSPoints: any, _binding: any, _flameFaces: any): Promise<boolean>;
171
- /**
172
- * 计算帧并返回 GPU 友好的 flat 格式(零拷贝,协方差预计算)
173
- * 🚀 性能优化版本:
174
- * - C++ 预计算协方差矩阵
175
- * - 零拷贝直接访问 WASM 内存http://localhost:3000/us/
176
- * - 直接输出 GPU 格式 [pos3, color4, cov6]
177
- */
178
- computeCompleteFrameFlat(params?: {
179
- frameIndex?: number;
180
- }): Promise<Float32Array | null>;
181
- /**
182
- * 计算帧并返回 GPU 友好的 flat 格式(从 FLAME 参数)
183
- * 🔑 用于 Realtime: 接受自定义 FLAME 参数并计算 Splat
184
- */
185
- computeFrameFlatFromParams(flameParams: FlameParams): Promise<Float32Array | null>;
186
77
  }
187
- export {};
188
- //# sourceMappingURL=avatarCoreAdapter.d.ts.map
@@ -58,7 +58,11 @@ export declare class AvatarCoreMemoryManager {
58
58
  /**
59
59
  * 创建 AvatarCharacterData 结构体 - 新版 Emscripten 方式
60
60
  */
61
- createCharacterData(shapeBuffer: ArrayBuffer, plyBuffer: ArrayBuffer): number;
61
+ createCharacterData(shapeBuffer: ArrayBuffer, plyBuffer: ArrayBuffer, characterId?: string): {
62
+ dataPtr: number;
63
+ shapePtr: number;
64
+ plyPtr: number;
65
+ };
62
66
  /**
63
67
  * 读取 AvatarFlameParams 结构体数据
64
68
  * Used to extract current animation frame parameters from WASM memory
@@ -138,4 +142,3 @@ export declare class AvatarCoreMemoryManager {
138
142
  };
139
143
  }
140
144
  export {};
141
- //# sourceMappingURL=avatarCoreMemory.d.ts.map
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@spatialwalk/avatarkit",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.7",
4
+ "version": "1.0.0-beta.71",
5
5
  "packageManager": "pnpm@10.18.2",
6
- "description": "SPAvatar SDK - 3D Gaussian Splatting Avatar Rendering SDK",
7
- "author": "SPAvatar Team",
6
+ "description": "AvatarKit SDK - 3D Gaussian Splatting Avatar Rendering SDK",
7
+ "author": "AvatarKit Team",
8
8
  "license": "MIT",
9
9
  "keywords": [
10
10
  "avatar",
@@ -19,6 +19,10 @@
19
19
  "types": "./dist/index.d.ts",
20
20
  "import": "./dist/index.js"
21
21
  },
22
+ "./vite": {
23
+ "types": "./vite.d.ts",
24
+ "import": "./vite.js"
25
+ },
22
26
  "./*": {
23
27
  "types": "./dist/*.d.ts",
24
28
  "import": "./dist/*.js"
@@ -30,28 +34,35 @@
30
34
  "files": [
31
35
  "README.md",
32
36
  "CHANGELOG.md",
33
- "dist"
37
+ "dist",
38
+ "vite.js",
39
+ "vite.d.ts"
34
40
  ],
35
41
  "scripts": {
36
- "build": "SDK_BUILD=true vite build --mode library",
42
+ "build": "SDK_BUILD=true vite build --mode library && npm run build:vite-plugin",
43
+ "build:vite-plugin": "tsc vite.ts --outDir . --module esnext --target es2020 --moduleResolution bundler --esModuleInterop --skipLibCheck --declaration --declarationMap",
37
44
  "dev": "vite build --mode library --watch",
38
45
  "clean": "rm -rf dist",
39
46
  "typecheck": "tsc --noEmit",
40
47
  "test": "cd tests && pnpm test",
41
48
  "test:watch": "cd tests && pnpm run test:watch",
42
- "test:e2e": "cd tests && pnpm run test:e2e"
49
+ "test:e2e": "cd tests && pnpm run test:e2e",
50
+ "test:perf": "cd tests && pnpm run test:perf"
43
51
  },
44
52
  "peerDependencies": {
45
- "@webgpu/types": "*"
53
+ "@webgpu/types": "*",
54
+ "vite": "^5.0.0"
46
55
  },
47
56
  "dependencies": {
48
57
  "@bufbuild/protobuf": "^2.10.0",
49
58
  "@guiiai/logg": "^1.2.4",
50
- "nanoid": "^5.1.6"
59
+ "nanoid": "^5.1.6",
60
+ "posthog-js": "^1.310.1"
51
61
  },
52
62
  "devDependencies": {
53
63
  "@types/node": "^20.11.30",
54
64
  "@webgpu/types": "^0.1.65",
65
+ "tsx": "^4.20.6",
55
66
  "typescript": "^5.0.0",
56
67
  "vite": "^5.0.0",
57
68
  "vite-plugin-dts": "^4.5.4"
package/vite.d.ts ADDED
@@ -0,0 +1,20 @@
1
+ import type { Plugin } from 'vite';
2
+ /**
3
+ * Vite plugin for @spatialwalk/avatarkit
4
+ * Automatically handles WASM file configuration for development and production builds
5
+ *
6
+ * @example
7
+ * ```ts
8
+ * import { defineConfig } from 'vite'
9
+ * import { avatarkitVitePlugin } from '@spatialwalk/avatarkit/vite'
10
+ *
11
+ * export default defineConfig({
12
+ * plugins: [
13
+ * avatarkitVitePlugin()
14
+ * ]
15
+ * })
16
+ * ```
17
+ */
18
+ export declare function avatarkitVitePlugin(): Plugin;
19
+ export default avatarkitVitePlugin;
20
+ //# sourceMappingURL=vite.d.ts.map
package/vite.js ADDED
@@ -0,0 +1,126 @@
1
+ import { copyFileSync, existsSync, writeFileSync, readdirSync, readFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ /**
4
+ * Vite plugin for @spatialwalk/avatarkit
5
+ * Automatically handles WASM file configuration for development and production builds
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * import { defineConfig } from 'vite'
10
+ * import { avatarkitVitePlugin } from '@spatialwalk/avatarkit/vite'
11
+ *
12
+ * export default defineConfig({
13
+ * plugins: [
14
+ * avatarkitVitePlugin()
15
+ * ]
16
+ * })
17
+ * ```
18
+ */
19
+ export function avatarkitVitePlugin() {
20
+ let rootDir;
21
+ return {
22
+ name: 'avatarkit-wasm',
23
+ // 保存项目根目录
24
+ configResolved(config) {
25
+ rootDir = config.root;
26
+ },
27
+ // 开发服务器 MIME 类型配置
28
+ configureServer(server) {
29
+ server.middlewares.use((req, res, next) => {
30
+ if (req.url?.endsWith('.wasm')) {
31
+ res.setHeader('Content-Type', 'application/wasm');
32
+ }
33
+ next();
34
+ });
35
+ },
36
+ // 构建时自动复制 WASM 文件和生成 headers
37
+ closeBundle() {
38
+ if (!rootDir)
39
+ return;
40
+ const wasmSourceDir = join(rootDir, 'node_modules/@spatialwalk/avatarkit/dist');
41
+ // 先查找并读取 JS glue 文件,提取它引用的 WASM 文件名
42
+ let wasmFileName = null;
43
+ if (existsSync(wasmSourceDir)) {
44
+ const files = readdirSync(wasmSourceDir);
45
+ const wasmJsFile = files.find((f) => f.startsWith('avatar_core_wasm') && f.endsWith('.js'));
46
+ if (wasmJsFile) {
47
+ const wasmJsSource = join(wasmSourceDir, wasmJsFile);
48
+ try {
49
+ const jsContent = readFileSync(wasmJsSource, 'utf-8');
50
+ // 从 JS 文件中提取 WASM 文件名
51
+ // 匹配 avatar_core_wasm-{hash}.wasm 或 avatar_core_wasm.wasm
52
+ // 使用更精确的正则,匹配带引号或不带引号的情况
53
+ const wasmMatch = jsContent.match(/["'`]?avatar_core_wasm[-\w]*\.wasm["'`]?/g);
54
+ if (wasmMatch && wasmMatch.length > 0) {
55
+ // 取第一个匹配,去掉引号
56
+ wasmFileName = wasmMatch[0].replace(/["'`]/g, '');
57
+ }
58
+ }
59
+ catch (error) {
60
+ console.warn('⚠️ [avatarkit] Could not read JS glue file:', error);
61
+ }
62
+ }
63
+ }
64
+ // 如果从 JS 文件中找到了 WASM 文件名,使用它;否则回退到默认名称
65
+ const targetWasmName = wasmFileName || 'avatar_core_wasm.wasm';
66
+ const wasmSource = join(wasmSourceDir, targetWasmName);
67
+ const wasmDest = join(rootDir, `dist/assets/${targetWasmName}`);
68
+ const wasmJsDest = join(rootDir, 'dist/assets/avatar_core_wasm.js');
69
+ const headersDest = join(rootDir, 'dist/_headers');
70
+ // 复制 WASM 文件
71
+ if (existsSync(wasmSource)) {
72
+ copyFileSync(wasmSource, wasmDest);
73
+ console.log(`✅ [avatarkit] Copied WASM file to dist/assets/${targetWasmName}`);
74
+ }
75
+ else {
76
+ console.warn(`⚠️ [avatarkit] WASM file not found: ${wasmSource}`);
77
+ if (wasmFileName) {
78
+ console.warn(` Expected file: ${targetWasmName} (extracted from JS glue file)`);
79
+ }
80
+ }
81
+ // 复制 WASM JS glue 文件
82
+ if (existsSync(wasmSourceDir)) {
83
+ const files = readdirSync(wasmSourceDir);
84
+ const wasmJsFile = files.find((f) => f.startsWith('avatar_core_wasm') && f.endsWith('.js'));
85
+ if (wasmJsFile) {
86
+ const wasmJsSource = join(wasmSourceDir, wasmJsFile);
87
+ copyFileSync(wasmJsSource, wasmJsDest);
88
+ console.log(`✅ [avatarkit] Copied WASM JS file to dist/assets/avatar_core_wasm.js (from ${wasmJsFile})`);
89
+ }
90
+ else {
91
+ console.log('ℹ️ [avatarkit] WASM JS file not found (may be handled by Vite):', wasmSourceDir);
92
+ }
93
+ }
94
+ // 生成 _headers 文件(用于 Cloudflare Pages 等平台)
95
+ const headersContent = '/*.wasm\n Content-Type: application/wasm\n';
96
+ writeFileSync(headersDest, headersContent);
97
+ console.log('✅ [avatarkit] Created _headers file for Cloudflare Pages');
98
+ },
99
+ // 自动配置 Vite 选项
100
+ config() {
101
+ return {
102
+ optimizeDeps: {
103
+ exclude: ['@spatialwalk/avatarkit']
104
+ },
105
+ assetsInclude: ['**/*.wasm'],
106
+ build: {
107
+ assetsInlineLimit: 0, // 确保 WASM 文件不被内联
108
+ rollupOptions: {
109
+ output: {
110
+ assetFileNames: (assetInfo) => {
111
+ // WASM 文件使用固定名称
112
+ if (assetInfo.name?.endsWith('.wasm')) {
113
+ return 'assets/[name][extname]';
114
+ }
115
+ // 其他资源使用 hash
116
+ return 'assets/[name]-[hash][extname]';
117
+ }
118
+ }
119
+ }
120
+ }
121
+ };
122
+ }
123
+ };
124
+ }
125
+ // 默认导出
126
+ export default avatarkitVitePlugin;