@helix3/helix-cli 0.1.18-helix3.266 → 0.1.18-helix3.268

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.
@@ -433,7 +433,8 @@ function validateTextureBinding(value, outputRoot, label) {
433
433
  }
434
434
  const colorSpace = object(binding.colorSpace, `${label}.colorSpace`);
435
435
  const colorKeys = Object.keys(colorSpace).sort();
436
- if (colorKeys.some((key) => key !== 'compressionSettings' && key !== 'srgb')) {
436
+ const SUPPORTED_COLOR_SPACE_KEYS = ['compressionSettings', 'flipGreenChannel', 'srgb'];
437
+ if (colorKeys.some((key) => !SUPPORTED_COLOR_SPACE_KEYS.includes(key))) {
437
438
  fail(`${label}.colorSpace contains unsupported metadata`);
438
439
  }
439
440
  if ('srgb' in colorSpace && typeof colorSpace.srgb !== 'boolean') {
@@ -442,6 +443,9 @@ function validateTextureBinding(value, outputRoot, label) {
442
443
  if ('compressionSettings' in colorSpace) {
443
444
  nonEmptyString(colorSpace.compressionSettings, `${label}.colorSpace.compressionSettings`);
444
445
  }
446
+ if ('flipGreenChannel' in colorSpace && typeof colorSpace.flipGreenChannel !== 'boolean') {
447
+ fail(`${label}.colorSpace.flipGreenChannel must be a boolean`);
448
+ }
445
449
 
446
450
  const texturePath = resolve(outputRoot, relativePath);
447
451
  containedPath(outputRoot, texturePath, label);
@@ -61,7 +61,9 @@ function fixture(profileOverrides = {}) {
61
61
  " if (process.env.HELIX_TEST_SIDECAR_KIND === 'missing') continue;",
62
62
  " const bindingSha = process.env.HELIX_TEST_SIDECAR_KIND === 'hash-mismatch' ? 'f'.repeat(64) : textureSha;",
63
63
  " const bindingPath = process.env.HELIX_TEST_SIDECAR_KIND === 'escape' ? '../escaped.png' : 'textures/' + bindingSha + '.png';",
64
- " const sidecar = { schemaVersion: 'helix.bridge.unreal-material-sidecar/1', asset: { slug: job.slug, sourceMeshAssetPath: job.assetPath }, materials: [{ slotIndex: 0, slotName: 'Body', importedSlotName: 'Body_skin00', sourceMaterialAssetPath: '/Game/Materials/MI_Body.MI_Body', sourceRootMaterialAssetPath: '/Game/Materials/M_Body.M_Body', parameters: { scalars: { Roughness: 0.5 }, vectors: { Tint: { r: 1, g: 0.5, b: 0.25, a: 1 } }, textures: { BaseColor: { sourceAssetPath: '/Game/Textures/T_Body.T_Body', path: bindingPath, sha256: bindingSha, sizeBytes: textureBytes.length, colorSpace: { srgb: true, compressionSettings: 'TC_Default' } } } } }] };",
64
+ " const colorSpace = { srgb: true, compressionSettings: 'TC_Default' };",
65
+ " if (process.env.HELIX_TEST_SIDECAR_KIND === 'flip-green') colorSpace.flipGreenChannel = true;",
66
+ " const sidecar = { schemaVersion: 'helix.bridge.unreal-material-sidecar/1', asset: { slug: job.slug, sourceMeshAssetPath: job.assetPath }, materials: [{ slotIndex: 0, slotName: 'Body', importedSlotName: 'Body_skin00', sourceMaterialAssetPath: '/Game/Materials/MI_Body.MI_Body', sourceRootMaterialAssetPath: '/Game/Materials/M_Body.M_Body', parameters: { scalars: { Roughness: 0.5 }, vectors: { Tint: { r: 1, g: 0.5, b: 0.25, a: 1 } }, textures: { BaseColor: { sourceAssetPath: '/Game/Textures/T_Body.T_Body', path: bindingPath, sha256: bindingSha, sizeBytes: textureBytes.length, colorSpace } } } }] };",
65
67
  " const sidecarPath = join(dirname(job.outputPath), job.slug + '.materials.json');",
66
68
  " if (process.env.HELIX_TEST_SIDECAR_KIND === 'corrupt') writeFileSync(sidecarPath, '{');",
67
69
  " else if (process.env.HELIX_TEST_SIDECAR_KIND === 'symlink') symlinkSync(process.env.HELIX_TEST_INVOCATION, sidecarPath);",
@@ -272,3 +274,15 @@ test('does not walk into Binaries/Intermediate/Saved/DerivedDataCache when findi
272
274
  const response = JSON.parse(result.stdout);
273
275
  assert.equal(response.artifacts[0].kind, 'format.fbx');
274
276
  });
277
+
278
+ test('accepts a material sidecar texture binding that records flipGreenChannel', () => {
279
+ // export_skeletal_mesh.py (texture_color_space) has recorded flipGreenChannel for every
280
+ // texture since the "Flip Green Channel" DirectX/OpenGL convention was added, but this
281
+ // handler's own sidecar validator never learned the key — every real export failed with
282
+ // "colorSpace contains unsupported metadata" until now.
283
+ const entry = fixture();
284
+ const result = run(entry, { HELIX_TEST_SIDECAR_KIND: 'flip-green' });
285
+ assert.equal(result.status, 0, result.stderr);
286
+ const sidecar = JSON.parse(readFileSync(join(entry.output, 'base-male.materials.json'), 'utf8'));
287
+ assert.equal(sidecar.materials[0].parameters.textures.BaseColor.colorSpace.flipGreenChannel, true);
288
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helix3/helix-cli",
3
- "version": "0.1.18-helix3.266",
3
+ "version": "0.1.18-helix3.268",
4
4
  "description": "helix — the HELIX creator CLI: scaffold, validate, and publish Instant Worlds",
5
5
  "main": "dist/lib.js",
6
6
  "types": "dist/lib.d.ts",