@spatialwalk/avatarkit 1.0.0-beta.76 → 1.0.0-beta.77

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/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { b, c, m, f, d, j, g, C, i, D, E, k, h, L, R, n } from "./index-ZN-iK3b8.js";
1
+ import { b, c, m, f, d, j, g, C, i, D, E, k, h, L, R, n } from "./index-CTh2onXJ.js";
2
2
  export {
3
3
  b as Avatar,
4
4
  c as AvatarController,
@@ -0,0 +1,137 @@
1
+ /**
2
+ * FLAME GPU Buffers 管理类
3
+ *
4
+ * 管理所有 FLAME 模板数据的 GPU 缓冲区
5
+ * - 模板数据在初始化时一次性上传 (~31MB)
6
+ * - 每帧参数通过 uniform buffer 更新 (460 bytes)
7
+ */
8
+ /**
9
+ * FLAME 模板数据结构
10
+ */
11
+ export interface FLAMETemplateData {
12
+ vTemplate: Float32Array;
13
+ vertexCount: number;
14
+ shapedirs: Float32Array;
15
+ shapeParamCount: number;
16
+ posedirs: Float32Array;
17
+ poseParamCount: number;
18
+ jRegressor: Float32Array;
19
+ jointCount: number;
20
+ lbsWeights: Float32Array;
21
+ parents: Int32Array;
22
+ faces: Uint32Array;
23
+ faceCount: number;
24
+ staticOffset: Float32Array | null;
25
+ staticOffsetCount: number;
26
+ }
27
+ /**
28
+ * 🚀 活跃Shape参数(零参数过滤优化)
29
+ */
30
+ export interface ActiveShapeParams {
31
+ activeIndices: Uint32Array;
32
+ activeValues: Float32Array;
33
+ count: number;
34
+ }
35
+ /**
36
+ * FLAME 帧参数 (从动画中获取)
37
+ * 🚀 优化: 移除 shapeParams (静态数据,只需上传一次)
38
+ */
39
+ export interface FLAMEFrameParams {
40
+ exprParams: Float32Array;
41
+ rotation: Float32Array;
42
+ translation: Float32Array;
43
+ neckPose: Float32Array;
44
+ jawPose: Float32Array;
45
+ eyesPose: Float32Array;
46
+ eyelid: Float32Array;
47
+ }
48
+ /**
49
+ * GPU Buffer 集合
50
+ */
51
+ export interface FLAMEGPUBufferSet {
52
+ vTemplate: GPUBuffer;
53
+ shapedirs: GPUBuffer;
54
+ posedirs: GPUBuffer;
55
+ jRegressor: GPUBuffer;
56
+ lbsWeights: GPUBuffer;
57
+ parents: GPUBuffer;
58
+ faces: GPUBuffer;
59
+ staticOffset: GPUBuffer | null;
60
+ activeShapeIndices: GPUBuffer;
61
+ activeShapeValues: GPUBuffer;
62
+ frameParams: GPUBuffer;
63
+ metadata: GPUBuffer;
64
+ }
65
+ export declare class FLAMEGPUBuffers {
66
+ private device;
67
+ private buffers;
68
+ private vertexCount;
69
+ private faceCount;
70
+ private jointCount;
71
+ private shapeParamCount;
72
+ private poseParamCount;
73
+ private staticOffsetCount;
74
+ private activeShapeCount;
75
+ private paramDataCache;
76
+ /**
77
+ * 初始化 GPU 缓冲区并上传模板数据
78
+ * 🚀 优化: 需要传入 characterHandle 以获取静态 shape parameters
79
+ * @param activeShapeParams 活跃shape参数(零参数过滤优化,可选)
80
+ */
81
+ initialize(device: GPUDevice, templateData: FLAMETemplateData, _shapeParams: Float32Array, activeShapeParams?: ActiveShapeParams): void;
82
+ /**
83
+ * 创建 Storage Buffer 并上传数据
84
+ */
85
+ private createStorageBuffer;
86
+ /**
87
+ * 创建帧参数 Uniform Buffer
88
+ * 🚀 优化: 移除 shapeParams,减小 70% 大小
89
+ *
90
+ * Layout (std140):
91
+ * - exprParams: vec4[25] (100 floats, padded)
92
+ * - rotation: vec4 (3 floats + padding)
93
+ * - translation: vec4 (3 floats + padding)
94
+ * - neckPose: vec4 (3 floats + padding)
95
+ * - jawPose: vec4 (3 floats + padding)
96
+ * - eyesPose: vec4[2] (6 floats, split into 2 vec4)
97
+ * - eyelid: vec4 (2 floats + padding)
98
+ */
99
+ private createFrameParamsBuffer;
100
+ /**
101
+ * 创建元数据 Uniform Buffer
102
+ *
103
+ * Layout:
104
+ * - vertexCount: u32
105
+ * - faceCount: u32
106
+ * - jointCount: u32
107
+ * - shapeParamCount: u32
108
+ * - poseParamCount: u32
109
+ * - staticOffsetCount: u32
110
+ * (padding to 256 bytes for alignment)
111
+ */
112
+ private createMetadataBuffer;
113
+ /**
114
+ * 更新每帧参数
115
+ * 🚀 优化: 移除 shapeParams 打包,减少 70% 上传量
116
+ */
117
+ updateFrameParams(params: FLAMEFrameParams): void;
118
+ /**
119
+ * 获取所有缓冲区
120
+ */
121
+ getBuffers(): FLAMEGPUBufferSet;
122
+ /**
123
+ * 获取元数据
124
+ */
125
+ getMetadata(): {
126
+ vertexCount: number;
127
+ faceCount: number;
128
+ jointCount: number;
129
+ shapeParamCount: number;
130
+ poseParamCount: number;
131
+ staticOffsetCount: number;
132
+ };
133
+ /**
134
+ * 清理资源
135
+ */
136
+ destroy(): void;
137
+ }
@@ -0,0 +1,71 @@
1
+ import { FLAMEGPUBufferSet } from './flameGPUBuffers';
2
+ /**
3
+ * FLAME Pipeline 输出
4
+ */
5
+ export interface FLAMEPipelineOutput {
6
+ faceGeometries: GPUBuffer;
7
+ faceCount: number;
8
+ }
9
+ export declare class FLAMEPipeline {
10
+ private device;
11
+ private buffers;
12
+ private vertexCount;
13
+ private faceCount;
14
+ private jointCount;
15
+ private shapeBlendPipeline;
16
+ private poseDeformPipeline;
17
+ private jointRegressPipeline;
18
+ private fkPipeline;
19
+ private lbsPipeline;
20
+ private faceGeometryPipeline;
21
+ private shapeBlendParamsBindGroup;
22
+ private poseDeformParamsBindGroup;
23
+ private jointRegressMetadataBindGroup;
24
+ private fkParamsBindGroup;
25
+ private lbsMetadataBindGroup;
26
+ private shapeBlendBindGroup;
27
+ private poseDeformBindGroup;
28
+ private jointRegressBindGroup;
29
+ private fkBindGroup;
30
+ private lbsBindGroup;
31
+ private faceGeometryParamsBindGroup;
32
+ private faceGeometryBindGroup;
33
+ private vShapedBuffer;
34
+ private vPosedBuffer;
35
+ private jointsBuffer;
36
+ private jointTransformsBuffer;
37
+ private vDeformedBuffer;
38
+ private faceGeometriesBuffer;
39
+ constructor(device: GPUDevice, buffers: FLAMEGPUBufferSet, vertexCount: number, faceCount: number, jointCount: number);
40
+ private initialize;
41
+ /**
42
+ * 创建中间缓冲区
43
+ */
44
+ private createIntermediateBuffers;
45
+ /**
46
+ * 清零所有中间缓冲区 (避免未初始化的垃圾数据)
47
+ * 🔧 关键修复: LBS shader 如果某些顶点权重全为0,会跳过不写入,导致保留垃圾数据
48
+ */
49
+ private clearIntermediateBuffers;
50
+ /**
51
+ * 创建计算管线
52
+ */
53
+ private createComputePipelines;
54
+ /**
55
+ * 创建单个计算管线
56
+ */
57
+ private createPipeline;
58
+ /**
59
+ * 创建绑定组
60
+ */
61
+ private createBindGroups;
62
+ /**
63
+ * 计算一帧 FLAME (主入口)
64
+ * 🚀 优化: 拆分为6个独立pass,支持详细的GPU profiling
65
+ */
66
+ compute(commandEncoder: GPUCommandEncoder): FLAMEPipelineOutput;
67
+ /**
68
+ * 清理资源
69
+ */
70
+ destroy(): void;
71
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * GPU Radix Sort - FFX 风格实现
3
+ *
4
+ * 核心思想:不用 atomicAdd 来决定写入位置,而是通过分层 Prefix Sum 预计算
5
+ *
6
+ * 每个 Pass (处理 8-bit,共 4 个 pass):
7
+ * 1. Histogram: 每个 workgroup 统计局部 histogram
8
+ * 2. Scan: 对所有 workgroup 的 histogram 做 prefix sum
9
+ * 3. Scatter: 根据预计算的位置写入
10
+ */
11
+ export interface GPURadixSortOptions {
12
+ device: GPUDevice;
13
+ maxSplatCount: number;
14
+ }
15
+ export declare class GPURadixSort {
16
+ private device;
17
+ private maxSplatCount;
18
+ private paddedCount;
19
+ private numWorkgroups;
20
+ private depthPipeline;
21
+ private histogramPipeline;
22
+ private scanPipeline;
23
+ private addBlockSumsPipeline;
24
+ private scatterPipeline;
25
+ private reversePipeline;
26
+ private uniformBuffer;
27
+ private paramsBuffer;
28
+ private scanParamsBuffer;
29
+ private keysBuffer0;
30
+ private keysBuffer1;
31
+ private valuesBuffer0;
32
+ private valuesBuffer1;
33
+ private histogramBuffer;
34
+ private blockSumsBuffer;
35
+ private blockSumsBuffer2;
36
+ private positionsBuffer;
37
+ constructor(options: GPURadixSortOptions);
38
+ private initialize;
39
+ setPositionsBuffer(buffer: GPUBuffer): void;
40
+ sortAsync(viewMatrix: Float32Array, splatCount: number): Promise<GPUBuffer>;
41
+ private runReversePass;
42
+ private runDepthPass;
43
+ private runHistogramPass;
44
+ private runPrefixSum;
45
+ private runScatterPass;
46
+ destroy(): void;
47
+ }
@@ -0,0 +1,97 @@
1
+ /**
2
+ * WebGPU Transform Pipeline
3
+ *
4
+ * 管理3DGS Transform的GPU计算:
5
+ * - Original Splats Buffer (一次性上传)
6
+ * - Face Geometry Buffer (每帧更新)
7
+ * - Transformed Output Buffer (GPU输出)
8
+ */
9
+ export declare class TransformPipeline {
10
+ private device;
11
+ private computePipeline;
12
+ private bindGroup;
13
+ private originalSplatsBuffer;
14
+ private faceGeometryBuffer;
15
+ private transformedOutputBuffer;
16
+ private positionsOutputBuffer;
17
+ private viewMatrixBuffer;
18
+ private depthsOutputBuffer;
19
+ private splatCount;
20
+ private faceCount;
21
+ private usesExternalFaceGeometryBuffer;
22
+ constructor(device: GPUDevice);
23
+ /**
24
+ * 初始化Pipeline
25
+ */
26
+ initialize(): Promise<void>;
27
+ /**
28
+ * 上传Original Splats (一次性调用)
29
+ * @param originalSplatsData Float32Array, 每个splat 16 floats (64 bytes)
30
+ * @param splatCount splat数量
31
+ */
32
+ uploadOriginalSplats(originalSplatsData: Float32Array, splatCount: number): void;
33
+ /**
34
+ * 🆕 设置外部 GPU FaceGeometry Buffer(GPU FLAME 路径)
35
+ * @param externalBuffer 外部 GPU buffer(来自 FLAME Pipeline 的 faceGeometriesBuffer)
36
+ * @param faceCount face 数量
37
+ */
38
+ setFaceGeometryBufferFromGPU(externalBuffer: GPUBuffer, faceCount: number): void;
39
+ /**
40
+ * 更新Face Geometry Buffer (每帧调用) - CPU 路径
41
+ * @param faceGeometryData Float32Array, 每个face 8 floats (32 bytes)
42
+ */
43
+ updateFaceGeometry(faceGeometryData: Float32Array): void;
44
+ /**
45
+ * 执行Transform计算 (在给定的command encoder中)
46
+ * @param commandEncoder 外部command encoder (与render共享以保证顺序)
47
+ */
48
+ executeInEncoder(commandEncoder: GPUCommandEncoder): void;
49
+ /**
50
+ * 获取Transformed Output Buffer (供渲染器使用)
51
+ */
52
+ getTransformedOutputBuffer(): GPUBuffer | null;
53
+ /**
54
+ * 🚀 获取Positions Output Buffer (供排序使用)
55
+ */
56
+ getPositionsOutputBuffer(): GPUBuffer | null;
57
+ /**
58
+ * 🆕 获取Depths Output Buffer (供GPU排序使用)
59
+ */
60
+ getDepthsOutputBuffer(): GPUBuffer | null;
61
+ /**
62
+ * 🆕 更新View Matrix (每帧调用)
63
+ * @param viewMatrix 4x4 view matrix
64
+ */
65
+ updateViewMatrix(viewMatrix: Float32Array): void;
66
+ /**
67
+ * 获取Splat数量
68
+ */
69
+ getSplatCount(): number;
70
+ /**
71
+ * 创建Transformed Output Buffer
72
+ * 格式: position[3] + color[4] + covariance[6] = 13 floats = 52 bytes
73
+ */
74
+ private createTransformedOutputBuffer;
75
+ /**
76
+ * 🚀 创建Positions Output Buffer (用于排序)
77
+ * 格式: position[3] = 3 floats = 12 bytes per splat
78
+ */
79
+ private createPositionsOutputBuffer;
80
+ /**
81
+ * 🆕 创建View Matrix Buffer
82
+ */
83
+ private createViewMatrixBuffer;
84
+ /**
85
+ * 🆕 创建Depths Output Buffer (用于GPU排序)
86
+ * 格式: depth (Uint32) = 4 bytes per splat
87
+ */
88
+ private createDepthsOutputBuffer;
89
+ /**
90
+ * 创建Bind Group
91
+ */
92
+ private createBindGroup;
93
+ /**
94
+ * 清理资源
95
+ */
96
+ destroy(): void;
97
+ }
@@ -1,4 +1,5 @@
1
1
  import { I3DGSRenderer, Transform } from '../renderer';
2
+ import { FLAMETemplateData, FLAMEFrameParams, ActiveShapeParams } from './flameGPUBuffers';
2
3
  export declare class WebGPURenderer implements I3DGSRenderer {
3
4
  private canvas;
4
5
  private backgroundColor;
@@ -13,6 +14,13 @@ export declare class WebGPURenderer implements I3DGSRenderer {
13
14
  private splatDataBuffer;
14
15
  private storageBindGroup;
15
16
  private bindGroupNeedsUpdate;
17
+ private transformPipeline;
18
+ private useGPUTransform;
19
+ private flamePipeline;
20
+ private flameGPUBuffers;
21
+ private useGPUFLAME;
22
+ private gpuRadixSort;
23
+ private useGPURadixSort;
16
24
  private splatCount;
17
25
  private presentationFormat;
18
26
  private alpha;
@@ -56,10 +64,54 @@ export declare class WebGPURenderer implements I3DGSRenderer {
56
64
  * 🚀 完全消除 CPU 重排序开销
57
65
  */
58
66
  loadSplatsFromPackedData(packedData: Float32Array, pointCount: number, sortOrder?: Uint32Array): void;
67
+ /**
68
+ * 🆕 上传原始Splats数据到GPU (一次性调用,角色加载时)
69
+ * @param originalSplatsData Float32Array, 每个splat 16 floats (64 bytes)
70
+ * @param splatCount splat数量
71
+ */
72
+ loadOriginalSplats(originalSplatsData: Float32Array, splatCount: number): void;
73
+ /**
74
+ * 🆕 更新Face Geometry (每帧调用,用于GPU Transform优化)
75
+ * @param faceGeometryData Float32Array, 每个face 8 floats (32 bytes)
76
+ */
77
+ updateFaceGeometry(faceGeometryData: Float32Array): void;
78
+ /**
79
+ * 🆕 加载 FLAME 模板数据到 GPU (一次性调用,角色加载时)
80
+ * @param templateData FLAME 模板数据
81
+ * @param shapeParams Shape 参数 [300]
82
+ * @param activeShapeParams 活跃shape参数(零参数过滤优化,可选)
83
+ */
84
+ loadFLAMETemplateData(templateData: FLAMETemplateData, shapeParams: Float32Array, activeShapeParams?: ActiveShapeParams): void;
85
+ /**
86
+ * 🆕 更新 FLAME 帧参数 (每帧调用)
87
+ * @param frameParams FLAME 帧参数
88
+ */
89
+ updateFLAMEFrameParams(frameParams: FLAMEFrameParams): void;
90
+ /**
91
+ * 🆕 获取是否使用 GPU Transform 路径
92
+ */
93
+ getUseGPUTransform(): boolean;
94
+ /**
95
+ * 🆕 获取是否使用 GPU FLAME 路径
96
+ */
97
+ getUseGPUFLAME(): boolean;
98
+ /**
99
+ * 🆕 使用Face Geometry渲染 (GPU Transform优化路径)
100
+ * 数据流: Face Geometry → GPU Transform → Render
101
+ *
102
+ * 支持两种模式:
103
+ * 1. CPU FLAME 路径:传入 faceGeometryData(从 CPU 计算)
104
+ * 2. GPU FLAME 路径:传入 frameParams(在 GPU 上计算 FLAME)
105
+ */
106
+ renderWithFaceGeometry(faceGeometryDataOrFrameParams: Float32Array | FLAMEFrameParams, viewMatrix: Float32Array, projectionMatrix: Float32Array, screenSize: [number, number], transform?: Transform): Promise<void>;
59
107
  /**
60
108
  * 渲染一帧
61
109
  */
62
110
  render(viewMatrix: Float32Array, projectionMatrix: Float32Array, screenSize: [number, number], transform?: Transform): void;
111
+ /**
112
+ * 🆕 渲染逻辑(提取为独立方法,供Transform和传统路径共用)
113
+ */
114
+ private renderWithCommandEncoder;
63
115
  /**
64
116
  * 将 render texture 绘制到屏幕(应用 transform)
65
117
  */
@@ -72,6 +124,11 @@ export declare class WebGPURenderer implements I3DGSRenderer {
72
124
  * 更新背景颜色
73
125
  */
74
126
  updateBackgroundColor(backgroundColor: [number, number, number, number]): void;
127
+ /**
128
+ * 🔍 关键修复:从GPU读取transform后的positions,进行深度排序,更新sortIndexBuffer
129
+ * 这解决了第一帧GPU路径渲染异常的问题(未排序导致渲染顺序错误)
130
+ */
131
+ private updateSortIndexFromGPU;
75
132
  /**
76
133
  * 清理资源
77
134
  */
@@ -3,8 +3,7 @@
3
3
  */
4
4
  export declare enum Environment {
5
5
  cn = "cn",
6
- intl = "intl",
7
- test = "test"
6
+ intl = "intl"
8
7
  }
9
8
  export declare enum DrivingServiceMode {
10
9
  /** Driven by SDK directly */
@@ -74,4 +74,53 @@ export declare class AvatarCoreAdapter {
74
74
  */
75
75
  releaseCurrentCharacter(): void;
76
76
  load3DGSData(_original3DGSPoints: any, _binding: any, _flameFaces: any): Promise<boolean>;
77
+ /**
78
+ * 🆕 GPU 路径: 计算帧并返回 Face Geometry 数据
79
+ */
80
+ computeFrameAsFaceGeometry(params?: {
81
+ frameIndex?: number;
82
+ characterId?: string;
83
+ }): Promise<Float32Array | null>;
84
+ /**
85
+ * 🆕 获取原始3DGS点数据 (一次性调用)
86
+ */
87
+ getOriginalSplatsData(): Promise<{
88
+ data: Float32Array;
89
+ count: number;
90
+ } | null>;
91
+ /**
92
+ * 🆕 获取角色 Shape 参数
93
+ */
94
+ getCharacterShapeParams(characterId?: string): Promise<{
95
+ params: number[];
96
+ } | null>;
97
+ /**
98
+ * 🆕 获取 FLAME 模板数据(用于 GPU FLAME Pipeline)
99
+ */
100
+ getFLAMETemplateData(characterId?: string): Promise<FLAMETemplateData | null>;
101
+ }
102
+ export interface FLAMETemplateData {
103
+ vTemplate: Float32Array;
104
+ vertexCount: number;
105
+ shapedirs: Float32Array;
106
+ shapeParamCount: number;
107
+ posedirs: Float32Array;
108
+ poseParamCount: number;
109
+ jRegressor: Float32Array;
110
+ jointCount: number;
111
+ lbsWeights: Float32Array;
112
+ parents: Int32Array;
113
+ faces: Uint32Array;
114
+ faceCount: number;
115
+ staticOffset: Float32Array | null;
116
+ staticOffsetCount: number;
117
+ }
118
+ export interface FLAMEIntermediateResults {
119
+ vShaped: Float32Array | null;
120
+ vPosed: Float32Array | null;
121
+ joints: Float32Array | null;
122
+ jointTransforms: Float32Array | null;
123
+ vDeformed: Float32Array | null;
124
+ vertexCount: number;
125
+ jointCount: number;
77
126
  }
@@ -108,6 +108,19 @@ export declare class AvatarCoreMemoryManager {
108
108
  * ⚠️ 使用 getValue 逐个读取,避免动态内存的 HEAPF32 detachment 问题
109
109
  */
110
110
  readSplatPointFlatArray(arrayPtr: number): Float32Array | null;
111
+ /**
112
+ * 🆕 读取 AvatarFaceGeometryArray 结构体数据 (WebGPU优化路径)
113
+ * 每个Face Geometry: center[3] + scale + quat[4] = 8 floats
114
+ */
115
+ readFaceGeometryArray(arrayPtr: number): Float32Array | null;
116
+ /**
117
+ * 🆕 读取 AvatarOriginalSplatArray 结构体数据 (WebGPU优化路径)
118
+ * 每个Original Splat: 15 floats + 1 int32 = 64 bytes
119
+ */
120
+ readOriginalSplatArray(arrayPtr: number): {
121
+ data: Float32Array;
122
+ count: number;
123
+ } | null;
111
124
  /**
112
125
  * 读取AvatarMeshData结构体数据
113
126
  */
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@spatialwalk/avatarkit",
3
3
  "type": "module",
4
- "version": "1.0.0-beta.76",
4
+ "version": "1.0.0-beta.77",
5
+ "packageManager": "pnpm@10.18.2",
5
6
  "description": "AvatarKit SDK - 3D Gaussian Splatting Avatar Rendering SDK",
6
7
  "author": "AvatarKit Team",
7
8
  "license": "MIT",
@@ -37,6 +38,17 @@
37
38
  "vite.js",
38
39
  "vite.d.ts"
39
40
  ],
41
+ "scripts": {
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",
44
+ "dev": "vite build --mode library --watch",
45
+ "clean": "rm -rf dist",
46
+ "typecheck": "tsc --noEmit",
47
+ "test": "cd tests && pnpm test",
48
+ "test:watch": "cd tests && pnpm run test:watch",
49
+ "test:e2e": "cd tests && pnpm run test:e2e",
50
+ "test:perf": "cd tests && pnpm run test:perf"
51
+ },
40
52
  "peerDependencies": {
41
53
  "@webgpu/types": "*",
42
54
  "vite": "^5.0.0"
@@ -54,16 +66,5 @@
54
66
  "typescript": "^5.0.0",
55
67
  "vite": "^5.0.0",
56
68
  "vite-plugin-dts": "^4.5.4"
57
- },
58
- "scripts": {
59
- "build": "SDK_BUILD=true vite build --mode library && npm run build:vite-plugin",
60
- "build:vite-plugin": "tsc vite.ts --outDir . --module esnext --target es2020 --moduleResolution bundler --esModuleInterop --skipLibCheck --declaration --declarationMap",
61
- "dev": "vite build --mode library --watch",
62
- "clean": "rm -rf dist",
63
- "typecheck": "tsc --noEmit",
64
- "test": "cd tests && pnpm test",
65
- "test:watch": "cd tests && pnpm run test:watch",
66
- "test:e2e": "cd tests && pnpm run test:e2e",
67
- "test:perf": "cd tests && pnpm run test:perf"
68
69
  }
69
- }
70
+ }