@needle-tools/gltf-build-pipeline 2.14.0 → 2.14.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to this package will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.14.1] - 2026-04-13
8
+ - fix: use `h32Raw` for buffer hashing to get consistent hashes between glb files with shared textures
9
+ - fix: texture guid creation now based on texture hash instead of filename+index for stable IDs
10
+ - fix: nullref when `slots` is undefined during texture resize logging
11
+ - fix: LOD textures now correctly inherit texture compression settings ([forum](https://forum.needle.tools/t/texture-compression-artefacts/2817/17))
12
+
7
13
  ## [2.14.0] - 2026-01-30
8
14
  - add: KHR_materials_pbrSpecularGlossiness extension support
9
15
  - fix: reduce `resample` tolerance to `1e-6` to avoid animation issues with some assets
@@ -5,9 +5,9 @@ import path from 'path';
5
5
  import { getVersion } from "../utils/version.js";
6
6
  // import * as CHECKDISCSPACE from 'check-disk-space'
7
7
  import xxhash from "xxhash-wasm";
8
- let hasher = null;
8
+ let xxHashModule = null;
9
9
  xxhash().then(module => {
10
- hasher = module.create32();
10
+ xxHashModule = module;
11
11
  });
12
12
  /**
13
13
  * Get the available space on the cache directory in bytes.
@@ -304,9 +304,9 @@ function hashObject(obj, depth = 0) {
304
304
  }
305
305
  }
306
306
  function hashBuffer(buffer, offset, length) {
307
- if (hasher) {
307
+ if (xxHashModule) {
308
308
  const view = new Uint8Array(buffer, offset, length);
309
- return hasher.update(view).digest();
309
+ return xxHashModule.h32Raw(view);
310
310
  }
311
311
  let hash = 0;
312
312
  const view = new Uint8Array(buffer, offset, length);
@@ -128,7 +128,8 @@ export async function packGLTF(inputFile, outputFile, options) {
128
128
  return true;
129
129
  }
130
130
  catch (err) {
131
- logger.error(`Packing of "${path.basename(inputFile)}" using version ${getVersion()} failed with error:\n${err.message}`);
131
+ const shortedStackTrace = err instanceof Error && err.stack ? err.stack.split('\n').slice(0, 2).join('\n') : '';
132
+ logger.error(`Packing of "${path.basename(inputFile)}" using version ${getVersion()} failed with error:\n${err.message}\n${shortedStackTrace}`);
132
133
  if (debug)
133
134
  throw err;
134
135
  return false;
@@ -151,6 +151,7 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
151
151
  return Promise.resolve();
152
152
  }
153
153
  let index = 0;
154
+ const textureHashCache = new Map();
154
155
  for (const texture of doc.getRoot().listTextures()) {
155
156
  const textureIndex = index++;
156
157
  const name = texture.getName();
@@ -177,8 +178,10 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
177
178
  continue;
178
179
  }
179
180
  else {
181
+ if (!textureHashCache.has(texture))
182
+ textureHashCache.set(texture, getHash(texture));
180
183
  settings = {
181
- guid: generateGuid(filename + "_texture_" + index.toString()),
184
+ guid: generateGuid(textureHashCache.get(texture)),
182
185
  maxSize: _options.size[0],
183
186
  };
184
187
  logger.debug(`[${NAME}] No settings found for texture[${index}] - will use default settings (maxSize: ${settings.maxSize}, guid: ${settings.guid})`);
@@ -213,7 +216,13 @@ export function make_progressive_textures(filePath, _options = TEXTURE_RESIZE_DE
213
216
  logger.debug(`[${NAME}] Skipping, texture[${textureIndex}] is already smaller than the requested size: ${currentSize}px <= ${settings.maxSize}px`);
214
217
  continue;
215
218
  }
216
- const textureGuid = settings.guid?.length ? settings.guid : generateGuid(filename + "_texture_" + index.toString());
219
+ if (!settings.guid?.length) {
220
+ if (!textureHashCache.has(texture))
221
+ textureHashCache.set(texture, getHash(texture));
222
+ const hash = textureHashCache.get(texture);
223
+ settings.guid = generateGuid(hash);
224
+ }
225
+ const textureGuid = settings.guid;
217
226
  /** This is the size of the texture that is embedded in the glTF. No LOD should be smaller than this */
218
227
  const maxSize = settings.maxSize;
219
228
  const LOD_LEVEL = new Array();
@@ -390,7 +399,7 @@ async function createTextureLod(args, opts) {
390
399
  logger.info("> Pass compression extension to new texture");
391
400
  const newExt = newDoc.createExtension(NEEDLE_compression_texture);
392
401
  const compressionSettings = compressionSettingsExt.getExtensionDefinition();
393
- if (compressionSettings?.mode === "none") {
402
+ if (compressionSettings?.mode === "none" || compressionSettings?.mode === "webp" || compressionSettings?.mode === "UASTC" || compressionSettings?.mode === "ETC1S") {
394
403
  // if the mode is set to None then we keep that setting for the new texture
395
404
  }
396
405
  else {
@@ -524,7 +533,7 @@ async function resizeTexture(options, texture, logger, uri, slots) {
524
533
  }
525
534
  dstWidth = Math.floor(dstWidth);
526
535
  dstHeight = Math.floor(dstHeight);
527
- logger.info(`→ Resize texture (${uri || texture.getName() || slots.join(", ")}) from ${srcWidth}x${srcHeight} to ${dstWidth}x${dstHeight}px`);
536
+ logger.info(`→ Resize texture (${uri || texture.getName() || slots?.join(", ")}) from ${srcWidth}x${srcHeight} to ${dstWidth}x${dstHeight}px`);
528
537
  // https://sharp.pixelplumbing.com/api-resize
529
538
  const buffer = await sharp(texture.getImage())
530
539
  .resize(dstWidth, dstHeight, {
@@ -1 +1 @@
1
- export declare const version = "2.14.0";
1
+ export declare const version = "2.14.1";
@@ -1 +1 @@
1
- export const version = "2.14.0";
1
+ export const version = "2.14.1";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@needle-tools/gltf-build-pipeline",
3
- "version": "2.14.0",
3
+ "version": "2.14.1",
4
4
  "description": "Pipeline and tools for optimizing gltf files using gltf-transform and compression settings within glTF extensions",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",