@helix3/helix-cli 0.1.14-helix3.207 → 0.1.14-helix3.208

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helix3/helix-cli",
3
- "version": "0.1.14-helix3.207",
3
+ "version": "0.1.14-helix3.208",
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",
@@ -2,7 +2,7 @@
2
2
  "schemaVersion": "helix.bridge-plugin/1",
3
3
  "id": "hypersonic.beamng-vehicle",
4
4
  "name": "BeamNG Vehicle Importer",
5
- "version": "0.6.0",
5
+ "version": "0.6.1",
6
6
  "trust": "local-untrusted",
7
7
  "description": "Assess, convert, texture, lower, and acceptance-test a BeamNG vehicle plus its exact configuration before HELIX packaging.",
8
8
  "permissions": [
@@ -162,7 +162,7 @@ const MAX_SEMANTIC_CLONE_CHARS = 128 * 1024 * 1024;
162
162
  * before downstream material deduplication. Texture indices are deliberately
163
163
  * untouched, so authored atlases remain one shared binary resource.
164
164
  */
165
- export function stampVehicleMaterialSemantics(json, familyVersions, familyDefaults) {
165
+ export function stampVehicleMaterialSemantics(json, familyVersions, familyDefaults, authoredBaseColorFactors) {
166
166
  // The prior two-argument injector API did not carry a Palette closure. Keep
167
167
  // it byte-semantically compatible rather than emitting a contradictory
168
168
  // family ID with a version belonging to a different family.
@@ -240,7 +240,19 @@ export function stampVehicleMaterialSemantics(json, familyVersions, familyDefaul
240
240
  if (defaults && Number.isFinite(defaults.roughness) && Number.isFinite(defaults.metallic)) {
241
241
  material.pbrMetallicRoughness ??= {};
242
242
  const alpha = material.pbrMetallicRoughness.baseColorFactor?.[3] ?? 1;
243
- material.pbrMetallicRoughness.baseColorFactor = [1, 1, 1, alpha];
243
+ // A family default is a FINISH — how rough and how metallic the surface is. It carries no colour,
244
+ // so there is nothing here that could stand in for one. Forcing [1,1,1] used to look harmless
245
+ // because the fixtures it was written against had no authored albedo at all; run it over a real
246
+ // converted car and every panel, tyre, grille and lens comes out white. That is exactly what
247
+ // shipped: all four Subaru renditions rendered as a white car while the Blender geometry they
248
+ // were built from still held the WRX blue.
249
+ // So restore the colour the SOURCE authored. Dropping the tint this injector wrote from a
250
+ // binding override is still correct on a family change (`bindingFor` strips it from the binding
251
+ // too) — that case is the one where the snapshot is absent or already neutral.
252
+ const authored = authoredBaseColorFactors?.[sourceIndex];
253
+ material.pbrMetallicRoughness.baseColorFactor = Array.isArray(authored) && authored.length >= 3
254
+ ? [authored[0], authored[1], authored[2], alpha]
255
+ : [1, 1, 1, alpha];
244
256
  material.pbrMetallicRoughness.roughnessFactor = defaults.roughness;
245
257
  material.pbrMetallicRoughness.metallicFactor = defaults.metallic;
246
258
  }
@@ -135,6 +135,15 @@ function applyMaterialBindings(json, rows, familyVersions, familyDefaults) {
135
135
  }
136
136
  }
137
137
  const byName = new Map((rows ?? []).map((row) => [row.name, row]));
138
+ // SNAPSHOT THE AUTHORED ALBEDO BEFORE ANY TINT IS WRITTEN OVER IT.
139
+ // A converted BeamNG body carries its colour in `baseColorFactor`, not in a texture: WRX blue, black
140
+ // tyre and grille, red indicator lenses, silver mirrors. Semantic stamping below re-tints a material
141
+ // when it moves to a different Palette family, and it is entitled to drop a tint IT wrote from a
142
+ // binding override — never the colour the conversion authored. Taking the snapshot here, before the
143
+ // tint loop, is what makes those two cases distinguishable one function later.
144
+ const authoredBaseColorFactors = (json.materials ?? []).map(
145
+ (material) => material?.pbrMetallicRoughness?.baseColorFactor,
146
+ );
138
147
  for (const material of json.materials ?? []) {
139
148
  if (!material || typeof material !== 'object' || Array.isArray(material)) {
140
149
  throw new Error('converter output GLB materials must contain objects');
@@ -161,7 +170,7 @@ function applyMaterialBindings(json, rows, familyVersions, familyDefaults) {
161
170
  ];
162
171
  }
163
172
  }
164
- stampVehicleMaterialSemantics(json, familyVersions, familyDefaults);
173
+ stampVehicleMaterialSemantics(json, familyVersions, familyDefaults, authoredBaseColorFactors);
165
174
  }
166
175
 
167
176
  function serializeGlbJson(json) {