@stowkit/three-loader 0.1.16 → 0.1.18

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 CHANGED
@@ -325,12 +325,12 @@ The package automatically copies required files on install:
325
325
 
326
326
  ```
327
327
  public/
328
- ├── stowkit_reader.wasm # WASM reader module
329
328
  └── stowkit/
330
- ├── basis/ # Basis Universal transcoder
329
+ ├── stowkit_reader.wasm # WASM reader module
330
+ ├── basis/ # Basis Universal transcoder
331
331
  │ ├── basis_transcoder.js
332
332
  │ └── basis_transcoder.wasm
333
- └── draco/ # Draco decoder
333
+ └── draco/ # Draco decoder
334
334
  ├── draco_decoder.js
335
335
  ├── draco_decoder.wasm
336
336
  └── draco_wasm_wrapper.js
@@ -1 +1 @@
1
- {"version":3,"file":"MeshParser.d.ts","sourceRoot":"","sources":["../src/MeshParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IAEnB;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY;IAcxD;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG;QAClE,QAAQ,EAAE,YAAY,CAAC;QACvB,UAAU,EAAE,gBAAgB,EAAE,CAAC;QAC/B,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC5B,YAAY,EAAE,YAAY,EAAE,CAAC;QAC7B,KAAK,EAAE,IAAI,EAAE,CAAC;QACd,WAAW,EAAE,WAAW,CAAC;KAC5B;IAoLD;;OAEG;WACU,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;IAyCrI;;OAEG;WACU,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IA2FtJ;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAK5B"}
1
+ {"version":3,"file":"MeshParser.d.ts","sourceRoot":"","sources":["../src/MeshParser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,WAAW,EAAE,MAAM,2CAA2C,CAAC;AAExE,MAAM,WAAW,gBAAgB;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB,EAAE,MAAM,CAAC;IAC/B,oBAAoB,EAAE,MAAM,CAAC;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,IAAI;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,qBAAqB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,SAAS,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,qBAAqB,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,YAAY;IACzB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED,qBAAa,UAAU;IAEnB;;OAEG;IACH,MAAM,CAAC,iBAAiB,CAAC,IAAI,EAAE,UAAU,GAAG,YAAY;IAyBxD;;OAEG;IACH,MAAM,CAAC,aAAa,CAAC,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAG;QAClE,QAAQ,EAAE,YAAY,CAAC;QACvB,UAAU,EAAE,gBAAgB,EAAE,CAAC;QAC/B,SAAS,EAAE,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC5B,YAAY,EAAE,YAAY,EAAE,CAAC;QAC7B,KAAK,EAAE,IAAI,EAAE,CAAC;QACd,WAAW,EAAE,WAAW,CAAC;KAC5B;IA4LD;;OAEG;WACU,cAAc,CAAC,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,cAAc,CAAC;IAyCrI;;OAEG;WACU,UAAU,CAAC,UAAU,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,aAAa,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC;IA2FtJ;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,UAAU;CAK5B"}
@@ -12,7 +12,7 @@ export interface StowKitLoaderOptions {
12
12
  dracoPath?: string;
13
13
  /**
14
14
  * Path to WASM reader module
15
- * @default '/stowkit_reader.wasm'
15
+ * @default '/stowkit/stowkit_reader.wasm'
16
16
  */
17
17
  wasmPath?: string;
18
18
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StowKitPack.d.ts","sourceRoot":"","sources":["../src/StowKitPack.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"StowKitPack.d.ts","sourceRoot":"","sources":["../src/StowKitPack.ts"],"names":[],"mappings":"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"}
@@ -9,13 +9,22 @@ class MeshParser {
9
9
  * Parse mesh metadata from binary data
10
10
  */
11
11
  static parseMeshMetadata(data) {
12
+ // NEW FORMAT: Skip past tag header
13
+ // Format: [4-byte tag_csv_length][CSV string][MeshMetadata struct]
12
14
  const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
15
+ const tagCsvLength = view.getUint32(0, true);
16
+ const metadataOffset = 4 + tagCsvLength;
17
+ if (metadataOffset >= data.length) {
18
+ throw new Error('Invalid metadata: tag header exceeds bounds');
19
+ }
20
+ const actualMetadata = data.slice(metadataOffset);
21
+ const metaView = new DataView(actualMetadata.buffer, actualMetadata.byteOffset, actualMetadata.byteLength);
13
22
  // MeshMetadata structure (140 bytes total when packed)
14
23
  const metadata = {
15
- meshGeometryCount: view.getUint32(0, true),
16
- materialCount: view.getUint32(4, true),
17
- nodeCount: view.getUint32(8, true),
18
- stringId: this.readString(data.slice(12, 140)) // 128 bytes for string
24
+ meshGeometryCount: metaView.getUint32(0, true),
25
+ materialCount: metaView.getUint32(4, true),
26
+ nodeCount: metaView.getUint32(8, true),
27
+ stringId: this.readString(actualMetadata.slice(12, 140)) // 128 bytes for string
19
28
  };
20
29
  return metadata;
21
30
  }
@@ -23,21 +32,24 @@ class MeshParser {
23
32
  * Parse complete mesh data including geometry, materials, and nodes
24
33
  */
25
34
  static parseMeshData(metadataBlob, dataBlob) {
26
- // Ensure we have at least the minimum metadata size
27
- if (metadataBlob.length < 140) {
28
- throw new Error(`Metadata blob too small: ${metadataBlob.length} bytes (expected at least 140)`);
29
- }
30
- const metadata = this.parseMeshMetadata(metadataBlob);
31
- // Check if the metadata blob contains just the header or all the mesh info
32
- const expectedMetadataSize = 140 +
35
+ // NEW FORMAT: Account for tag header at front
36
+ const view = new DataView(metadataBlob.buffer, metadataBlob.byteOffset, metadataBlob.byteLength);
37
+ const tagCsvLength = view.getUint32(0, true);
38
+ const tagHeaderSize = 4 + tagCsvLength;
39
+ const metadata = this.parseMeshMetadata(metadataBlob); // This already handles tag header
40
+ // Check if the metadata blob contains all the mesh info (shifted by tag header)
41
+ // Total expected size = tagHeaderSize + 140 (MeshMetadata) + geometries + materials + nodes
42
+ const expectedMetadataSize = tagHeaderSize + 140 +
33
43
  (metadata.meshGeometryCount * 40) + // Draco compressed (40 bytes each)
34
44
  (metadata.materialCount * 196) + // MaterialData header
35
45
  (metadata.nodeCount * 116);
36
46
  let hasExtendedMetadata = metadataBlob.length >= expectedMetadataSize;
37
- // If metadata only has the header, the mesh info might be at the start of the data blob
47
+ // If metadata has everything, read from metadataBlob (accounting for tag header)
48
+ // Otherwise, read from dataBlob (no tag header there)
38
49
  const sourceBlob = hasExtendedMetadata ? metadataBlob : dataBlob;
39
50
  const metaView = new DataView(sourceBlob.buffer, sourceBlob.byteOffset, sourceBlob.byteLength);
40
- let offset = hasExtendedMetadata ? 140 : 0; // Start after MeshMetadata if in metadata blob, or at beginning of data blob
51
+ // Offset: skip tag header + MeshMetadata struct if reading from metadata blob
52
+ let offset = hasExtendedMetadata ? (tagHeaderSize + 140) : 0;
41
53
  // Parse geometry infos (now Draco compressed!)
42
54
  const geometries = [];
43
55
  for (let i = 0; i < metadata.meshGeometryCount; i++) {
@@ -156,10 +168,16 @@ class MeshParser {
156
168
  });
157
169
  // Apply properties
158
170
  for (const prop of matData.properties) {
159
- if (prop.fieldName.toLowerCase() === 'tint' || prop.fieldName.toLowerCase().includes('color')) {
160
- // Apply color/tint
171
+ const fieldName = prop.fieldName.toLowerCase();
172
+ if (fieldName === 'tint' || fieldName.includes('color')) {
161
173
  mat.color = new THREE.Color(prop.value[0], prop.value[1], prop.value[2]);
162
174
  }
175
+ else if (fieldName === 'alphatest') {
176
+ if (prop.value[0] > 0) {
177
+ mat.alphaTest = 0.5;
178
+ mat.transparent = true;
179
+ }
180
+ }
163
181
  }
164
182
  materials.push(mat);
165
183
  }
@@ -327,15 +345,20 @@ class StowKitPack {
327
345
  * Parse skinned mesh from binary data
328
346
  */
329
347
  async parseSkinnedMesh(metadata, data) {
330
- // Parse skinned mesh metadata
348
+ // NEW FORMAT: Skip past tag header
331
349
  const view = new DataView(metadata.buffer, metadata.byteOffset, metadata.byteLength);
350
+ const tagCsvLength = view.getUint32(0, true);
351
+ const tagHeaderSize = 4 + tagCsvLength;
352
+ // Skip to actual metadata
353
+ const actualMetadata = metadata.slice(tagHeaderSize);
354
+ const metaView = new DataView(actualMetadata.buffer, actualMetadata.byteOffset, actualMetadata.byteLength);
332
355
  const decoder = new TextDecoder();
333
356
  // SkinnedMeshMetadata: 4 uint32s (16 bytes) THEN string_id[128] = 144 bytes total
334
- const meshGeometryCount = view.getUint32(0, true);
335
- const materialCount = view.getUint32(4, true);
336
- const nodeCount = view.getUint32(8, true);
337
- const boneCount = view.getUint32(12, true);
338
- const stringIdBytes = metadata.slice(16, 144);
357
+ const meshGeometryCount = metaView.getUint32(0, true);
358
+ const materialCount = metaView.getUint32(4, true);
359
+ const nodeCount = metaView.getUint32(8, true);
360
+ const boneCount = metaView.getUint32(12, true);
361
+ const stringIdBytes = actualMetadata.slice(16, 144);
339
362
  const stringIdNullIndex = stringIdBytes.indexOf(0);
340
363
  const stringId = decoder
341
364
  .decode(stringIdBytes.slice(0, stringIdNullIndex >= 0 ? stringIdNullIndex : 128))
@@ -348,21 +371,21 @@ class StowKitPack {
348
371
  // vertex_buffer_offset, vertex_buffer_size, index_buffer_offset, index_buffer_size, weights_offset, weights_size (48 bytes)
349
372
  // material_index, _padding (8 bytes)
350
373
  for (let g = 0; g < meshGeometryCount; g++) {
351
- if (offset + 72 > metadata.length) {
374
+ if (offset + 72 > actualMetadata.length) {
352
375
  throw new Error(`Metadata too small for geometry ${g}`);
353
376
  }
354
377
  geometryInfos.push({
355
- vertexCount: view.getUint32(offset, true),
356
- indexCount: view.getUint32(offset + 4, true),
357
- hasNormals: view.getUint32(offset + 8, true),
358
- hasUVs: view.getUint32(offset + 12, true),
359
- vertexBufferOffset: Number(view.getBigUint64(offset + 16, true)),
360
- vertexBufferSize: Number(view.getBigUint64(offset + 24, true)),
361
- indexBufferOffset: Number(view.getBigUint64(offset + 32, true)),
362
- indexBufferSize: Number(view.getBigUint64(offset + 40, true)),
363
- weightsOffset: Number(view.getBigUint64(offset + 48, true)),
364
- weightsSize: Number(view.getBigUint64(offset + 56, true)),
365
- materialIndex: view.getUint32(offset + 64, true)
378
+ vertexCount: metaView.getUint32(offset, true),
379
+ indexCount: metaView.getUint32(offset + 4, true),
380
+ hasNormals: metaView.getUint32(offset + 8, true),
381
+ hasUVs: metaView.getUint32(offset + 12, true),
382
+ vertexBufferOffset: Number(metaView.getBigUint64(offset + 16, true)),
383
+ vertexBufferSize: Number(metaView.getBigUint64(offset + 24, true)),
384
+ indexBufferOffset: Number(metaView.getBigUint64(offset + 32, true)),
385
+ indexBufferSize: Number(metaView.getBigUint64(offset + 40, true)),
386
+ weightsOffset: Number(metaView.getBigUint64(offset + 48, true)),
387
+ weightsSize: Number(metaView.getBigUint64(offset + 56, true)),
388
+ materialIndex: metaView.getUint32(offset + 64, true)
366
389
  // _padding at offset + 68 (ignored)
367
390
  });
368
391
  offset += 72;
@@ -375,15 +398,15 @@ class StowKitPack {
375
398
  const materialData = [];
376
399
  // Parse MaterialData headers
377
400
  for (let i = 0; i < materialCount; i++) {
378
- if (metadataOffset + 196 > metadata.length) {
401
+ if (metadataOffset + 196 > actualMetadata.length) {
379
402
  console.warn('Skinned mesh metadata truncated while reading material headers');
380
403
  break;
381
404
  }
382
- const nameBytes = metadata.slice(metadataOffset, metadataOffset + 64);
383
- const schemaIdBytes = metadata.slice(metadataOffset + 64, metadataOffset + 192);
405
+ const nameBytes = actualMetadata.slice(metadataOffset, metadataOffset + 64);
406
+ const schemaIdBytes = actualMetadata.slice(metadataOffset + 64, metadataOffset + 192);
384
407
  const name = decoder.decode(nameBytes.slice(0, nameBytes.indexOf(0) || 64));
385
408
  const schemaId = decoder.decode(schemaIdBytes.slice(0, schemaIdBytes.indexOf(0) || 128));
386
- const propertyCount = view.getUint32(metadataOffset + 192, true);
409
+ const propertyCount = metaView.getUint32(metadataOffset + 192, true);
387
410
  materialData.push({ name, schemaId, propertyCount, properties: [] });
388
411
  metadataOffset += 196;
389
412
  }
@@ -398,20 +421,20 @@ class StowKitPack {
398
421
  const mat = materialData[i];
399
422
  for (let p = 0; p < mat.propertyCount; p++) {
400
423
  try {
401
- if (metadataOffset + PROPERTY_STRIDE > metadata.length) {
424
+ if (metadataOffset + PROPERTY_STRIDE > actualMetadata.length) {
402
425
  break;
403
426
  }
404
- const fieldNameBytes = metadata.slice(metadataOffset, metadataOffset + 64);
427
+ const fieldNameBytes = actualMetadata.slice(metadataOffset, metadataOffset + 64);
405
428
  const fieldName = decoder
406
429
  .decode(fieldNameBytes.slice(0, fieldNameBytes.indexOf(0) || 64))
407
430
  .trim();
408
431
  const value = [
409
- view.getFloat32(metadataOffset + 64, true),
410
- view.getFloat32(metadataOffset + 68, true),
411
- view.getFloat32(metadataOffset + 72, true),
412
- view.getFloat32(metadataOffset + 76, true)
432
+ metaView.getFloat32(metadataOffset + 64, true),
433
+ metaView.getFloat32(metadataOffset + 68, true),
434
+ metaView.getFloat32(metadataOffset + 72, true),
435
+ metaView.getFloat32(metadataOffset + 76, true)
413
436
  ];
414
- const textureIdBytes = metadata.slice(metadataOffset + 80, metadataOffset + 144);
437
+ const textureIdBytes = actualMetadata.slice(metadataOffset + 80, metadataOffset + 144);
415
438
  const textureIdNullIndex = textureIdBytes.indexOf(0);
416
439
  const textureId = (textureIdNullIndex >= 0
417
440
  ? decoder.decode(textureIdBytes.slice(0, textureIdNullIndex))
@@ -433,17 +456,17 @@ class StowKitPack {
433
456
  const boneOriginalNames = [];
434
457
  const bindPoses = [];
435
458
  for (let i = 0; i < boneCount; i++) {
436
- if (metadataOffset + BONE_STRIDE > metadata.length) {
459
+ if (metadataOffset + BONE_STRIDE > actualMetadata.length) {
437
460
  throw new Error(`Skinned mesh metadata truncated while reading bone ${i}`);
438
461
  }
439
- const nameBytes = new Uint8Array(metadata.buffer, metadata.byteOffset + metadataOffset, 64);
462
+ const nameBytes = new Uint8Array(actualMetadata.buffer, actualMetadata.byteOffset + metadataOffset, 64);
440
463
  const nullIndex = nameBytes.indexOf(0);
441
464
  const rawName = decoder.decode(nameBytes.subarray(0, nullIndex >= 0 ? nullIndex : 64)).trim();
442
- const parentIndex = view.getInt32(metadataOffset + 64, true);
465
+ const parentIndex = metaView.getInt32(metadataOffset + 64, true);
443
466
  const offsetMatrix = new THREE.Matrix4();
444
467
  const matrixElements = new Float32Array(16);
445
468
  for (let j = 0; j < 16; j++) {
446
- matrixElements[j] = view.getFloat32(metadataOffset + 68 + j * 4, true);
469
+ matrixElements[j] = metaView.getFloat32(metadataOffset + 68 + j * 4, true);
447
470
  }
448
471
  offsetMatrix.fromArray(matrixElements);
449
472
  const sanitizedName = this.sanitizeTrackName(rawName);
@@ -504,7 +527,6 @@ class StowKitPack {
504
527
  // Apply non-texture properties
505
528
  for (const prop of mat.properties) {
506
529
  const fieldName = prop.fieldName.toLowerCase();
507
- // Handle color properties
508
530
  if (fieldName.includes('color') || fieldName.includes('tint')) {
509
531
  material.color.setRGB(prop.value[0], prop.value[1], prop.value[2]);
510
532
  }
@@ -514,6 +536,12 @@ class StowKitPack {
514
536
  else if (fieldName === 'roughness') {
515
537
  material.roughness = prop.value[0];
516
538
  }
539
+ else if (fieldName === 'alphatest') {
540
+ if (prop.value[0] > 0) {
541
+ material.alphaTest = 0.5;
542
+ material.transparent = true;
543
+ }
544
+ }
517
545
  }
518
546
  materials.push(material);
519
547
  }
@@ -833,32 +861,38 @@ class StowKitPack {
833
861
  * Parse animation clip from binary data
834
862
  */
835
863
  parseAnimationClip(metadata, data) {
864
+ // NEW FORMAT: Skip past tag header
836
865
  const view = new DataView(metadata.buffer, metadata.byteOffset, metadata.byteLength);
866
+ const tagCsvLength = view.getUint32(0, true);
867
+ const tagHeaderSize = 4 + tagCsvLength;
868
+ // Skip to actual metadata
869
+ const actualMetadata = metadata.slice(tagHeaderSize);
870
+ const metaView = new DataView(actualMetadata.buffer, actualMetadata.byteOffset, actualMetadata.byteLength);
837
871
  const decoder = new TextDecoder();
838
872
  // Parse AnimationClipMetadata (272 bytes total)
839
- const stringIdBytes = metadata.slice(0, 128);
873
+ const stringIdBytes = actualMetadata.slice(0, 128);
840
874
  const stringIdNullIndex = stringIdBytes.indexOf(0);
841
875
  const stringId = decoder.decode(stringIdBytes.slice(0, stringIdNullIndex >= 0 ? stringIdNullIndex : 128));
842
- const targetMeshIdBytes = metadata.slice(128, 256);
876
+ const targetMeshIdBytes = actualMetadata.slice(128, 256);
843
877
  const targetMeshIdNullIndex = targetMeshIdBytes.indexOf(0);
844
878
  decoder
845
879
  .decode(targetMeshIdBytes.slice(0, targetMeshIdNullIndex >= 0 ? targetMeshIdNullIndex : 128))
846
880
  .trim();
847
- const durationSeconds = view.getFloat32(256, true); // Duration in seconds (per C header)
848
- view.getFloat32(260, true); // For custom playback rate if needed
849
- const channelCount = view.getUint32(264, true);
850
- const boneCount = view.getUint32(268, true);
881
+ const durationSeconds = metaView.getFloat32(256, true); // Duration in seconds (per C header)
882
+ metaView.getFloat32(260, true); // For custom playback rate if needed
883
+ const channelCount = metaView.getUint32(264, true);
884
+ const boneCount = metaView.getUint32(268, true);
851
885
  // Parse AnimationChannel[] (starts at offset 272, each is 28 bytes)
852
886
  const channelsOffset = 272;
853
887
  const channels = [];
854
888
  for (let i = 0; i < channelCount; i++) {
855
889
  const chOffset = channelsOffset + i * 28;
856
890
  channels.push({
857
- boneIndex: view.getUint32(chOffset, true),
858
- keyframeType: view.getUint32(chOffset + 4, true),
859
- keyframeCount: view.getUint32(chOffset + 8, true),
860
- keyframeTimesOffset: Number(view.getBigUint64(chOffset + 12, true)),
861
- keyframeValuesOffset: Number(view.getBigUint64(chOffset + 20, true))
891
+ boneIndex: metaView.getUint32(chOffset, true),
892
+ keyframeType: metaView.getUint32(chOffset + 4, true),
893
+ keyframeCount: metaView.getUint32(chOffset + 8, true),
894
+ keyframeTimesOffset: Number(metaView.getBigUint64(chOffset + 12, true)),
895
+ keyframeValuesOffset: Number(metaView.getBigUint64(chOffset + 20, true))
862
896
  });
863
897
  }
864
898
  // Parse AnimationBoneInfo[] (starts after all channels, each is 68 bytes)
@@ -866,13 +900,13 @@ class StowKitPack {
866
900
  const bones = [];
867
901
  for (let i = 0; i < boneCount; i++) {
868
902
  const boneOffset = bonesOffset + i * 68;
869
- const nameBytes = metadata.slice(boneOffset, boneOffset + 64);
903
+ const nameBytes = actualMetadata.slice(boneOffset, boneOffset + 64);
870
904
  const nullIndex = nameBytes.indexOf(0);
871
905
  const rawName = decoder
872
906
  .decode(nameBytes.slice(0, nullIndex >= 0 ? nullIndex : 64))
873
907
  .trim();
874
908
  const sanitizedName = this.sanitizeTrackName(rawName);
875
- const parentIndex = view.getInt32(boneOffset + 64, true);
909
+ const parentIndex = metaView.getInt32(boneOffset + 64, true);
876
910
  bones.push({ name: rawName, parentIndex, sanitizedName });
877
911
  }
878
912
  // Create DataView for keyframe data
@@ -1065,7 +1099,7 @@ class StowKitLoader {
1065
1099
  * Initialize the loader (called automatically on first load)
1066
1100
  */
1067
1101
  static async initialize(options) {
1068
- const wasmPath = options?.wasmPath || '/stowkit_reader.wasm';
1102
+ const wasmPath = options?.wasmPath || '/stowkit/stowkit_reader.wasm';
1069
1103
  const basisPath = options?.basisPath || '/stowkit/basis/';
1070
1104
  const dracoPath = options?.dracoPath || '/stowkit/draco/';
1071
1105
  // Initialize reader