@auraindustry/aurajs 0.0.1 → 0.0.2

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": "@auraindustry/aurajs",
3
- "version": "0.0.1",
3
+ "version": "0.0.2",
4
4
  "description": "Write games in JavaScript, build native binaries.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/cli.mjs CHANGED
@@ -518,37 +518,18 @@ async function cmdBuild(args) {
518
518
  icon,
519
519
  }));
520
520
 
521
- console.log('\n aura build: JavaScript bundle complete.');
521
+ console.log('\n aura build: complete.');
522
522
  console.log(` Game: ${identity.name}`);
523
523
  console.log(` Version: ${identity.version}`);
524
- console.log(` Bundle: ${result.outFile}`);
525
- console.log(` Modules: ${result.moduleCount}`);
526
- console.log(` Hash: ${result.hash.slice(0, 8)}`);
527
524
  console.log(` Time: ${result.elapsedMs}ms`);
528
- console.log('');
529
- console.log(` Assets: ${assets.assetCount}`);
530
- console.log(` Asset mode: ${assets.mode}`);
531
- console.log(` Asset manifest hash: ${assets.manifestHash}`);
525
+ console.log(` Assets: ${assets.assetCount} (${assets.mode})`);
532
526
  console.log(
533
- ` Asset incremental: copied=${assets.incremental.copied} skipped=${assets.incremental.skipped} removed=${assets.incremental.removed} reusedPack=${assets.incremental.reusedPack}`,
527
+ ` Asset updates: copied=${assets.incremental.copied} skipped=${assets.incremental.skipped} removed=${assets.incremental.removed}`,
534
528
  );
535
- if (assets.packPath) {
536
- console.log(` Asset pack: ${assets.packPath}`);
537
- }
538
- console.log(` Asset manifest: ${assets.manifestPath}`);
539
- console.log(` Build manifest: ${buildManifestPath}`);
540
- console.log(` Host package: ${hostBinary.packageName}`);
541
- console.log(` Host binary: ${hostBinary.binaryPath}`);
542
- console.log(` Host cache: ${hostBinary.cacheStatus} (${hostBinary.cacheDir})`);
543
- for (const diagnostic of hostBinary.diagnostics || []) {
544
- console.log(` Host diagnostic: ${diagnostic}`);
545
- }
546
- console.log(` Executable: ${executablePath}`);
547
- console.log(` Executable base name: ${identity.executableBaseName}`);
548
529
  if (icon.status === 'copied') {
549
- console.log(` Icon: ${icon.outputPath}`);
530
+ console.log(' Icon: configured');
550
531
  } else {
551
- console.log(` Icon: ${icon.status} (${icon.reasonCode})`);
532
+ console.log(` Icon: ${icon.status}`);
552
533
  }
553
534
  console.log(` Output target: ${effectiveTarget}`);
554
535
 
@@ -585,11 +566,7 @@ async function cmdRun(args) {
585
566
  const built = await cmdBuild(args);
586
567
  const launchContract = built.buildManifestPath;
587
568
 
588
- console.log(' aura run: launching native host.');
589
- console.log(` Executable: ${built.executablePath}`);
590
- console.log(` Build manifest: ${launchContract}`);
591
- console.log(` Working dir: ${built.projectRoot}`);
592
- console.log('');
569
+ console.log('\n aura run: launching native host.\n');
593
570
 
594
571
  const child = spawnSync(built.executablePath, [launchContract], {
595
572
  cwd: built.projectRoot,
@@ -620,6 +620,10 @@ export const DEFAULT_CONFORMANCE_CASES = [
620
620
  { id: 'tilemap.queryRay', expression: "typeof aura.tilemap?.queryRay === 'function'" },
621
621
  { id: 'tilemap.queryRaycast', expression: "typeof aura.tilemap?.queryRaycast === 'function'" },
622
622
  { id: 'tilemap.query.invalid-handle.reason-code', expression: "(() => { const result = aura.tilemap.queryPoint(999999, { x: 0, y: 0 }); return result && result.ok === false && result.reasonCode === 'invalid_map_handle'; })()" },
623
+ {
624
+ id: 'tilemap.query.model-schema.deterministic',
625
+ expression: "(() => { const runSample = () => { const model = { width: 2, height: 2, tilewidth: 16, tileheight: 16, solidLayerNames: ['solid'], layers: [ { name: 'solid', width: 2, height: 2, data: [1, 0, 0, 0], properties: { solid: true } }, { name: 'dynamic', width: 2, height: 2, data: [0, 1, 0, 0], queryEnabled: true } ], solidCells: [ { x: 1, y: 0, layerIndex: 5, layerName: 'manual' }, { x: 1, y: 0, layerIndex: 5, layerName: 'manual' } ] }; const point = aura.tilemap.queryPoint(model, { x: 16.5, y: 0.5 }); const aabb = aura.tilemap.queryAABB(model, { x: 0, y: 0, w: 32, h: 16 }); const ray = aura.tilemap.queryRay(model, { x: 0.5, y: 0.5, dx: 1, dy: 0, maxDistance: 64 }); return { pointLayers: Array.isArray(point?.hits) ? point.hits.map((hit) => hit.layerIndex).join(',') : '', aabbLayers: Array.isArray(aabb?.hits) ? aabb.hits.map((hit) => hit.layerIndex).join(',') : '', rayLayer: Number(ray?.hitCell?.layerIndex ?? -1), pointOk: point?.ok === true, aabbOk: aabb?.ok === true, rayOk: ray?.ok === true, pointHit: point?.hit === true, aabbHit: aabb?.hit === true, rayHit: ray?.hit === true, invalidModelReason: aura.tilemap.queryPoint({ width: 2 }, { x: 0, y: 0 })?.reasonCode, invalidAabbReason: aura.tilemap.queryAABB(model, { x: 0, y: 0, w: 0, h: 1 })?.reasonCode }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.pointOk === true && first.aabbOk === true && first.rayOk === true && first.pointHit === true && first.aabbHit === true && first.rayHit === true && first.pointLayers === '1,5' && first.aabbLayers === '0,1,5' && first.rayLayer === 0 && first.invalidModelReason === 'invalid_model' && first.invalidAabbReason === 'invalid_aabb_args'; })()",
626
+ },
623
627
  ],
624
628
  frames: 1,
625
629
  source: `
@@ -708,6 +712,10 @@ export const DEFAULT_CONFORMANCE_CASES = [
708
712
  { id: 'tilemap.layer.setLayerFlags', expression: "typeof aura.tilemap?.setLayerFlags === 'function'" },
709
713
  { id: 'tilemap.layer.setLayerVisibility', expression: "typeof aura.tilemap?.setLayerVisibility === 'function'" },
710
714
  { id: 'tilemap.layer.setLayerCollision', expression: "typeof aura.tilemap?.setLayerCollision === 'function'" },
715
+ {
716
+ id: 'tilemap.mutation.reason-codes.expanded',
717
+ expression: "(() => { const runSample = () => { const fixture = { width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] } ], tilesets: [ { firstgid: 1, image: 'tiles-a.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 }, { firstgid: 5, image: 'tiles-b.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const invalidGidArgs = aura.tilemap.setRegion(mapId, 'ground', { x: 0, y: 0, w: 1, h: 1 }, 'bad'); const unmappedBoundary = aura.tilemap.setRegion(mapId, 'ground', { x: 0, y: 0, w: 1, h: 1 }, 2); const validBoundary = aura.tilemap.setRegion(mapId, 'ground', { x: 0, y: 0, w: 1, h: 1 }, 5); const invalidReplaceArgs = aura.tilemap.replaceRegion(mapId, 'ground', { x: 0, y: 0, w: 1, h: 1 }, 1, 'bad'); const invalidLayerFlags = aura.tilemap.setLayerFlags(mapId, 'ground', {}); const invalidVisibility = aura.tilemap.setLayerVisibility(mapId, 'ground', 'yes'); const invalidCollision = aura.tilemap.setLayerCollision(mapId, 'ground', 'yes'); const invalidLayer = aura.tilemap.removeRegion(mapId, 'missing', { x: 0, y: 0, w: 1, h: 1 }); const invalidHandle = aura.tilemap.setRegion(999999, 'ground', { x: 0, y: 0, w: 1, h: 1 }, 1); aura.tilemap.unload(mapId); return { invalidGidArgs: invalidGidArgs?.reasonCode, unmappedBoundary: unmappedBoundary?.reasonCode, validBoundaryOk: validBoundary?.ok === true, validBoundaryChanged: Number(validBoundary?.changedTiles || 0), invalidReplaceArgs: invalidReplaceArgs?.reasonCode, invalidLayerFlags: invalidLayerFlags?.reasonCode, invalidVisibility: invalidVisibility?.reasonCode, invalidCollision: invalidCollision?.reasonCode, invalidLayer: invalidLayer?.reasonCode, invalidHandle: invalidHandle?.reasonCode }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.invalidGidArgs === 'invalid_gid_args' && first.unmappedBoundary === 'unmapped_layer_gid' && first.validBoundaryOk === true && first.validBoundaryChanged === 1 && first.invalidReplaceArgs === 'invalid_replace_args' && first.invalidLayerFlags === 'invalid_layer_flags' && first.invalidVisibility === 'invalid_visibility_flag' && first.invalidCollision === 'invalid_collision_flag' && first.invalidLayer === 'invalid_layer_ref' && first.invalidHandle === 'invalid_map_handle'; })()",
718
+ },
711
719
  {
712
720
  id: 'tilemap.mutation.layer-controls.deterministic',
713
721
  expression: "(() => { const runSample = () => { const fixture = { width: 4, height: 4, tilewidth: 16, tileheight: 16, solidLayerNames: ['ground', 'hazards'], layers: [ { name: 'ground', type: 'tilelayer', width: 4, height: 4, data: Array.from({ length: 16 }, () => 1) }, { name: 'hazards', type: 'tilelayer', width: 4, height: 4, data: [0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const initial = aura.tilemap.queryPoint(mapId, { x: 16.5, y: 16.5 }); const setRegion = aura.tilemap.setRegion(mapId, 'ground', { x: 0, y: 0, w: 2, h: 1 }, 0); const topRow = aura.tilemap.queryAABB(mapId, { x: 0, y: 0, w: 32, h: 16 }); const removeRegion = aura.tilemap.removeRegion(mapId, 'hazards', { x: 1, y: 1, w: 1, h: 1 }); const afterRemove = aura.tilemap.queryPoint(mapId, { x: 16.5, y: 16.5 }); const replaceRegion = aura.tilemap.replaceRegion(mapId, 'ground', { x: 1, y: 1, w: 1, h: 1 }, 1, 0); const afterReplace = aura.tilemap.queryPoint(mapId, { x: 16.5, y: 16.5 }); const collisionOff = aura.tilemap.setLayerCollision(mapId, 'ground', false); const hazardsPoint = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 16.5 }); const visibilityOff = aura.tilemap.setLayerVisibility(mapId, 'hazards', false); const hiddenDraw = aura.tilemap.draw(mapId, { cull: false }); const flags = aura.tilemap.setLayerFlags(mapId, 'hazards', { visible: true, collision: false }); const shownDraw = aura.tilemap.draw(mapId, { cull: false }); const queryMuted = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 16.5 }); const groundCollisionOn = aura.tilemap.setLayerFlags(mapId, 'ground', { collision: true }); const hazardsCollisionOn = aura.tilemap.setLayerCollision(mapId, 'hazards', true); const queryRestored = aura.tilemap.queryPoint(mapId, { x: 32.5, y: 16.5 }); const invalidRegion = aura.tilemap.setRegion(mapId, 'ground', { x: 0, y: 0, w: 0, h: 1 }, 1); const invalidGid = aura.tilemap.setRegion(mapId, 'ground', { x: 0, y: 0, w: 1, h: 1 }, 999); const invalidFlags = aura.tilemap.setLayerFlags(mapId, 'ground', { collision: 'yes' }); const invalidLayer = aura.tilemap.setLayerVisibility(mapId, 'missing', true); aura.tilemap.unload(mapId); return { initialHits: Array.isArray(initial?.hits) ? initial.hits.length : -1, topRowHits: Array.isArray(topRow?.hits) ? topRow.hits.length : -1, afterRemoveHits: Array.isArray(afterRemove?.hits) ? afterRemove.hits.length : -1, afterReplaceHits: Array.isArray(afterReplace?.hits) ? afterReplace.hits.length : -1, hazardsHits: Array.isArray(hazardsPoint?.hits) ? hazardsPoint.hits.length : -1, queryMutedHits: Array.isArray(queryMuted?.hits) ? queryMuted.hits.length : -1, queryRestoredHits: Array.isArray(queryRestored?.hits) ? queryRestored.hits.length : -1, setChanged: setRegion?.changedTiles, removeChanged: removeRegion?.changedTiles, replaceChanged: replaceRegion?.changedTiles, collisionOff: collisionOff?.collision, visibilityOff: visibilityOff?.visible, hiddenOrder: hiddenDraw?.layerOrder?.join(','), shownOrder: shownDraw?.layerOrder?.join(','), flagsVisible: flags?.visible, flagsCollision: flags?.collision, groundCollisionOn: groundCollisionOn?.collision, hazardsCollisionOn: hazardsCollisionOn?.collision, invalidRegion: invalidRegion?.reasonCode, invalidGid: invalidGid?.reasonCode, invalidFlags: invalidFlags?.reasonCode, invalidLayer: invalidLayer?.reasonCode }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.initialHits === 2 && first.topRowHits === 0 && first.afterRemoveHits === 1 && first.afterReplaceHits === 0 && first.hazardsHits === 1 && first.queryMutedHits === 0 && first.queryRestoredHits === 2 && first.setChanged === 2 && first.removeChanged === 1 && first.replaceChanged === 1 && first.collisionOff === false && first.visibilityOff === false && first.hiddenOrder === 'ground' && first.shownOrder === 'ground,hazards' && first.flagsVisible === true && first.flagsCollision === false && first.groundCollisionOn === true && first.hazardsCollisionOn === true && first.invalidRegion === 'invalid_region_args' && first.invalidGid === 'unmapped_layer_gid' && first.invalidFlags === 'invalid_collision_flag' && first.invalidLayer === 'invalid_layer_ref'; })()",
@@ -952,7 +960,11 @@ export const DEFAULT_CONFORMANCE_CASES = [
952
960
  nativeChecks: [
953
961
  {
954
962
  id: 'optional.multiplayer.enabled.runtime',
955
- expression: "(() => { try { const api = aura.multiplayer; if (!api || typeof api !== 'object') return false; const methods = ['configure', 'host', 'join', 'leave', 'stop']; if (!methods.every((name) => typeof api[name] === 'function')) return false; const notDisabled = (invoke) => { try { invoke(); return true; } catch (e) { const msg = String(e); return !msg.includes('optional module \"multiplayer\" is disabled') && !msg.includes('modules.multiplayer = true') && !msg.includes('modules.multiplayer') && !msg.includes('[reason:optional_module_multiplayer_disabled]'); } }; return notDisabled(() => api.configure({ tickRate: 20 })) && notDisabled(() => api.host(7000)) && notDisabled(() => api.join('127.0.0.1', 7000)) && notDisabled(() => api.leave()) && notDisabled(() => api.stop()); } catch (_) { return false; } })()",
963
+ expression: "(() => { try { const api = aura.multiplayer; if (!api || typeof api !== 'object') return false; const methods = ['configure', 'host', 'join', 'leave', 'stop']; if (!methods.every((name) => typeof api[name] === 'function')) return false; const notDisabled = (invoke) => { try { invoke(); return true; } catch (e) { const msg = String(e); return !msg.includes('optional module \"multiplayer\" is disabled') && !msg.includes('modules.multiplayer = true') && !msg.includes('modules.multiplayer') && !msg.includes('[reason:optional_module_multiplayer_disabled]') && !msg.includes('not implemented yet'); } }; return notDisabled(() => api.configure({ tickRate: 20 })) && notDisabled(() => api.host(7000)) && notDisabled(() => api.join('127.0.0.1', 7000)) && notDisabled(() => api.leave()) && notDisabled(() => api.stop()); } catch (_) { return false; } })()",
964
+ },
965
+ {
966
+ id: 'optional.multiplayer.enabled.invalid-state.reason-code',
967
+ expression: "(() => { try { aura.multiplayer.leave(); return false; } catch (e) { const msg = String(e); return msg.includes('aura.multiplayer.leave() failed [reason:invalid_state]') && !msg.includes('optional module \"multiplayer\" is disabled') && !msg.includes('[reason:optional_module_multiplayer_disabled]') && !msg.includes('not implemented yet'); } })()",
956
968
  },
957
969
  ],
958
970
  nativeFrames: 2,
@@ -1371,11 +1383,15 @@ export const DEFAULT_CONFORMANCE_CASES = [
1371
1383
  },
1372
1384
  {
1373
1385
  id: 'particles.vfx.blend-layer.fixed-step.deterministic',
1374
- expression: "(() => { const runSample = (tag) => { const created = aura.particles.emit({ x: 24, y: 24, count: 8, life: 0.5, size: 2, speedMin: 12, speedMax: 12, direction: 0, spread: 0, loop: true, rate: 24 }); if (!created || created.ok !== true) return null; const emitterId = created.emitterId; const layer = aura.particles.setLayer(emitterId, 3); const blend = aura.particles.setBlend(emitterId, 'add'); const burst = aura.particles.burst(emitterId, { count: 5 }); const trace = []; for (const dt of [1 / 120, 1 / 30, 1 / 24, 1 / 15]) { const step = aura.particles.update(dt); const state = aura.particles.getState(emitterId); trace.push({ ok: !!step && step.ok === true, particles: state ? state.particles : null }); } const drawn = aura.particles.draw({ maxParticles: 64 }); const killed = aura.particles.kill(emitterId); const afterKill = aura.particles.getState(emitterId); return { tag, layerOk: !!layer && layer.ok === true, blendOk: !!blend && blend.ok === true, burstOk: !!burst && burst.ok === true, trace, drawn: drawn && drawn.ok === true ? drawn.drawnParticles : null, killed: !!killed && killed.ok === true, afterKillNull: afterKill === null }; }; const first = runSample('a'); const second = runSample('b'); if (!first || !second) return false; const normalizedFirst = JSON.stringify({ ...first, tag: 'x' }); const normalizedSecond = JSON.stringify({ ...second, tag: 'x' }); return normalizedFirst === normalizedSecond && first.layerOk === true && first.blendOk === true && first.burstOk === true && first.trace.every((entry) => entry.ok === true && Number.isFinite(entry.particles) && entry.particles >= 0) && Number.isFinite(first.drawn) && first.drawn > 0 && first.killed === true && first.afterKillNull === true; })()",
1386
+ expression: "(() => { const runSample = (tag) => { const createdA = aura.particles.emit({ x: 24, y: 24, count: 5, life: 0.5, size: 2, speedMin: 12, speedMax: 12, direction: 0, spread: 0, loop: true, rate: 24, layer: 3, blend: 'add' }); const createdB = aura.particles.emit({ x: 40, y: 24, count: 5, life: 0.5, size: 2, speedMin: 8, speedMax: 8, direction: 0, spread: 0, loop: true, rate: 12, layer: 1, blend: 'screen' }); if (!createdA || createdA.ok !== true || !createdB || createdB.ok !== true) return null; const emitterIdA = createdA.emitterId; const emitterIdB = createdB.emitterId; const layer = aura.particles.setLayer(emitterIdA, 3); const blend = aura.particles.setBlend(emitterIdA, 'add'); const burstA = aura.particles.burst(emitterIdA, { count: 4 }); const burstB = aura.particles.burst(emitterIdB); const trace = []; for (const dt of [1 / 120, 1 / 30, 1 / 24, 1 / 15]) { const step = aura.particles.update(dt); const stateA = aura.particles.getState(emitterIdA); const stateB = aura.particles.getState(emitterIdB); trace.push({ ok: !!step && step.ok === true, particlesA: stateA ? stateA.particles : null, particlesB: stateB ? stateB.particles : null }); } const drawn = aura.particles.draw({ maxParticles: 64 }); const order = Array.isArray(drawn?.drawOrder) ? drawn.drawOrder.map((entry) => `${entry.layer}:${entry.blend}:${entry.drawnParticles}`).join('|') : null; const killedA = aura.particles.kill(emitterIdA); const killedB = aura.particles.kill(emitterIdB); const afterKillA = aura.particles.getState(emitterIdA); const afterKillB = aura.particles.getState(emitterIdB); return { tag, layerOk: !!layer && layer.ok === true, blendOk: !!blend && blend.ok === true, burstASpawned: burstA?.spawned ?? null, burstBSpawned: burstB?.spawned ?? null, trace, drawn: drawn && drawn.ok === true ? drawn.drawnParticles : null, order, killedA: !!killedA && killedA.ok === true, killedB: !!killedB && killedB.ok === true, afterKillNull: afterKillA === null && afterKillB === null }; }; const first = runSample('a'); const second = runSample('b'); if (!first || !second) return false; const normalizedFirst = JSON.stringify({ ...first, tag: 'x' }); const normalizedSecond = JSON.stringify({ ...second, tag: 'x' }); return normalizedFirst === normalizedSecond && first.layerOk === true && first.blendOk === true && first.burstASpawned === 4 && first.burstBSpawned === 5 && first.trace.every((entry) => entry.ok === true && Number.isFinite(entry.particlesA) && Number.isFinite(entry.particlesB) && entry.particlesA >= 0 && entry.particlesB >= 0) && Number.isFinite(first.drawn) && first.drawn > 0 && (first.order === null || (typeof first.order === 'string' && first.order.length > 0)) && first.killedA === true && first.killedB === true && first.afterKillNull === true; })()",
1387
+ },
1388
+ {
1389
+ id: 'particles.vfx.stop-vs-kill.fixed-step.deterministic',
1390
+ expression: "(() => { const runSample = () => { const drainedEmitter = aura.particles.emit({ x: 0, y: 0, count: 3, life: 0.2, size: 1, speedMin: 6, speedMax: 6, direction: 0, spread: 0, loop: false }); const killedEmitter = aura.particles.emit({ x: 0, y: 0, count: 3, life: 0.2, size: 1, speedMin: 6, speedMax: 6, direction: 0, spread: 0, loop: true, rate: 30 }); if (!drainedEmitter?.ok || !killedEmitter?.ok) return null; const drainedId = drainedEmitter.emitterId; const killedId = killedEmitter.emitterId; const drained = aura.particles.stop(drainedId, { mode: 'drain' }); const drainedAfterStop = aura.particles.getState(drainedId); const killed = aura.particles.kill(killedId); const killedAfterKill = aura.particles.getState(killedId); for (const dt of [0.05, 0.05, 0.05, 0.05]) { aura.particles.update(dt); } const drainedAfterTick = aura.particles.getState(drainedId); const killedAfterTick = aura.particles.getState(killedId); return { drainedOk: !!drained && drained.ok === true, drainedRemovedAfterStop: drainedAfterStop === null, drainedPersistedAfterStop: drainedAfterStop !== null, killedOk: !!killed && killed.ok === true, killedRemovedAfterKill: killedAfterKill === null, drainedRemovedAfterTick: drainedAfterTick === null, killedRemovedAfterTick: killedAfterTick === null }; }; const first = runSample(); const second = runSample(); return !!first && !!second && JSON.stringify(first) === JSON.stringify(second) && first.drainedOk === true && (first.drainedRemovedAfterStop === true || first.drainedPersistedAfterStop === true) && first.killedOk === true && first.killedRemovedAfterKill === true && first.drainedRemovedAfterTick === true && first.killedRemovedAfterTick === true; })()",
1375
1391
  },
1376
1392
  {
1377
1393
  id: 'particles.vfx.reason-codes.stable',
1378
- expression: "(() => { const collect = () => { const invalidLayerId = aura.particles.setLayer('bad-id', 1); const invalidBlendId = aura.particles.setBlend('bad-id', 'add'); const invalidBlendMode = aura.particles.setBlend(999999, 'unsupported'); const invalidBurstArgs = aura.particles.burst('bad-id'); const invalidBurstCount = aura.particles.burst(999999, { count: 0 }); const invalidKillId = aura.particles.kill('bad-id'); const invalidStopId = aura.particles.stop('bad-id'); return { invalidLayerId, invalidBlendId, invalidBlendMode, invalidBurstArgs, invalidBurstCount, invalidKillId, invalidStopId }; }; const first = collect(); const second = collect(); const stable = JSON.stringify(first) === JSON.stringify(second); const reasoned = Object.values(first).every((entry) => entry && entry.ok === false && typeof (entry.reasonCode || entry.reason) === 'string' && (entry.reasonCode || entry.reason).length > 0); return stable && reasoned; })()",
1394
+ expression: "(() => { const reasonOf = (entry) => (entry && (entry.reasonCode || entry.reason)) || null; const collect = () => { const created = aura.particles.emit({ x: 0, y: 0, count: 1 }); if (!created || created.ok !== true) return null; const emitterId = created.emitterId; const invalidLayerId = aura.particles.setLayer('bad-id', 1); const invalidBlendId = aura.particles.setBlend('bad-id', 'add'); const invalidLayer = aura.particles.setLayer(emitterId, -1); const invalidBlendMode = aura.particles.setBlend(emitterId, 'unsupported'); const invalidBurstArgs = aura.particles.burst(emitterId, 'bad'); const invalidBurstCount = aura.particles.burst(emitterId, { count: 0 }); const invalidStopMode = aura.particles.stop(emitterId, { mode: 'pause' }); const invalidKillId = aura.particles.kill('bad-id'); const missingKill = aura.particles.kill(999999); const cleaned = aura.particles.kill(emitterId); return { invalidLayerId: reasonOf(invalidLayerId), invalidBlendId: reasonOf(invalidBlendId), invalidLayer: reasonOf(invalidLayer), invalidBlendMode: reasonOf(invalidBlendMode), invalidBurstArgs: reasonOf(invalidBurstArgs), invalidBurstCount: reasonOf(invalidBurstCount), invalidStopMode: reasonOf(invalidStopMode), invalidKillId: reasonOf(invalidKillId), missingKill: reasonOf(missingKill), cleaned: !!cleaned && cleaned.ok === true }; }; const first = collect(); const second = collect(); return !!first && !!second && JSON.stringify(first) === JSON.stringify(second) && first.invalidLayerId === 'invalid_emitter_id' && first.invalidBlendId === 'invalid_emitter_id' && first.invalidLayer === 'invalid_layer' && first.invalidBlendMode === 'invalid_blend_mode' && first.invalidBurstArgs === 'invalid_burst_options' && first.invalidBurstCount === 'invalid_burst_count' && (first.invalidStopMode === null || first.invalidStopMode === 'invalid_stop_mode') && first.invalidKillId === 'invalid_emitter_id' && first.missingKill === 'missing_emitter' && (first.cleaned === true || first.invalidStopMode === null); })()",
1379
1395
  },
1380
1396
  ],
1381
1397
  source: `
@@ -1403,8 +1419,12 @@ export const DEFAULT_CONFORMANCE_CASES = [
1403
1419
  expression: "(() => { const runSample = () => { const baseline = aura.draw3d.getPostFXState(); aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('colorGrade'); aura.draw3d.removePostFXPass('vignette'); aura.draw3d.removePostFXPass('fxaa'); const setBloom = aura.draw3d.setPostFXPass('bloom', { strength: 1.25, radius: 0.6, threshold: 0.7 }); const setFxaa = aura.draw3d.setPostFXPass('fxaa', { enabled: true, strength: 1.0 }); const setColorGrade = aura.draw3d.setPostFXPass('colorGrade', { strength: 0.8 }); const disableBloom = aura.draw3d.setPostFXEnabled('bloom', false); const enableBloom = aura.draw3d.setPostFXEnabled('bloom', true); const removeFxaa = aura.draw3d.removePostFXPass('fxaa'); const setVignette = aura.draw3d.setPostFXPass('vignette', { strength: 0.4, radius: 0.9 }); const state = aura.draw3d.getPostFXState(); return { status: [setBloom?.reasonCode, setFxaa?.reasonCode, setColorGrade?.reasonCode, disableBloom?.reasonCode, enableBloom?.reasonCode, removeFxaa?.reasonCode, setVignette?.reasonCode].join('|'), order: Array.isArray(state?.passes) ? state.passes.map((pass) => pass.pass).join('|') : '', enabled: state?.enabledPasses, total: state?.totalPasses, fingerprint: state?.orderFingerprint, mutationDelta: Number(state?.mutationCount || 0) - Number(baseline?.mutationCount || 0), lastReasonCode: state?.lastReasonCode, lastOk: state?.lastOk }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.status === 'postfx_ok|postfx_ok|postfx_ok|postfx_ok|postfx_ok|postfx_ok|postfx_ok' && first.order === 'colorGrade|bloom|vignette' && first.total === 3 && first.enabled === 3 && Number.isFinite(first.fingerprint) && first.fingerprint > 0 && first.mutationDelta === 11 && first.lastReasonCode === 'postfx_ok' && first.lastOk === true; })()",
1404
1420
  },
1405
1421
  {
1406
- id: 'draw3d.postfx.reason-codes',
1407
- expression: "(() => { aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('fxaa'); const invalidPassEmpty = aura.draw3d.setPostFXPass('', {}); const invalidPassType = aura.draw3d.setPostFXPass(42, {}); const unsupportedPass = aura.draw3d.setPostFXPass('ssao', {}); const invalidOptions = aura.draw3d.setPostFXPass('bloom', 'bad'); const configured = aura.draw3d.setPostFXPass('bloom', { strength: 1.0 }); const invalidEnabled = aura.draw3d.setPostFXEnabled('bloom', 'yes'); const removeConfigured = aura.draw3d.removePostFXPass('bloom'); const missingToggle = aura.draw3d.setPostFXEnabled('fxaa', true); const missingRemove = aura.draw3d.removePostFXPass('fxaa'); return configured?.ok === true && removeConfigured?.ok === true && invalidPassEmpty?.ok === false && invalidPassEmpty?.reasonCode === 'postfx_invalid_pass_name' && invalidPassType?.ok === false && invalidPassType?.reasonCode === 'postfx_invalid_pass_name' && unsupportedPass?.ok === false && unsupportedPass?.reasonCode === 'postfx_pass_unsupported' && invalidOptions?.ok === false && invalidOptions?.reasonCode === 'postfx_invalid_options' && invalidEnabled?.ok === false && invalidEnabled?.reasonCode === 'postfx_invalid_enabled' && missingToggle?.ok === false && missingToggle?.reasonCode === 'postfx_pass_missing' && missingRemove?.ok === false && missingRemove?.reasonCode === 'postfx_pass_missing'; })()",
1422
+ id: 'draw3d.postfx.target-chain.custom-pass.deterministic',
1423
+ expression: "(() => { const runSample = () => { const baseline = aura.draw3d.getPostFXState(); aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('colorGrade'); aura.draw3d.removePostFXPass('vignette'); aura.draw3d.removePostFXPass('fxaa'); aura.draw3d.removePostFXPass('custom:filmgrain'); aura.draw3d.removePostFXPass('custom:glow'); const setBloom = aura.draw3d.setPostFXPass('bloom', { strength: 1.1, targetChain: { intermediateTargets: ['mainA', 'mainB', 'mainA'], pingPong: true, composeMode: 'additive' } }); const setCustom = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 0.75, threshold: 0.33 } }); const updateCustom = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 0.5, threshold: 0.2 } }); const setFilmgrain = aura.draw3d.setPostFXPass('custom:filmgrain', { customParams: { amount: 0.2, grain: 0.1 } }); const state = aura.draw3d.getPostFXState(); const targetChain = state?.targetChain || {}; const customGlow = Array.isArray(state?.passes) ? state.passes.find((pass) => pass.pass === 'custom:glow') : null; const customParams = customGlow?.customParams || {}; const customParamKeys = Object.keys(customParams).sort().join('|'); return { status: [setBloom?.reasonCode, setCustom?.reasonCode, updateCustom?.reasonCode, setFilmgrain?.reasonCode].join('|'), order: Array.isArray(state?.passes) ? state.passes.map((pass) => pass.pass).join('|') : '', enabled: state?.enabledPasses, total: state?.totalPasses, customPassCount: state?.customPassCount, targetChainTargets: Array.isArray(targetChain?.intermediateTargets) ? targetChain.intermediateTargets.join('|') : '', targetChainCount: targetChain?.intermediateTargetCount, targetChainPingPong: targetChain?.pingPong === true, targetChainComposeMode: targetChain?.composeMode, targetChainFingerprint: state?.targetChainFingerprint, customParamFingerprint: state?.customParamFingerprint, customGlowIsCustom: customGlow?.isCustom === true, customGlowParamKeys: customParamKeys, customGlowIntensity: customParams?.intensity, customGlowThreshold: customParams?.threshold, mutationDelta: Number(state?.mutationCount || 0) - Number(baseline?.mutationCount || 0), lastReasonCode: state?.lastReasonCode, lastOk: state?.lastOk }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.status === 'postfx_ok|postfx_ok|postfx_ok|postfx_ok' && first.order === 'bloom|custom:filmgrain|custom:glow' && first.total === 3 && first.enabled === 3 && first.customPassCount === 2 && first.targetChainTargets === 'maina|mainb' && first.targetChainCount === 2 && first.targetChainPingPong === true && first.targetChainComposeMode === 'additive' && Number.isFinite(first.targetChainFingerprint) && first.targetChainFingerprint > 0 && Number.isFinite(first.customParamFingerprint) && first.customParamFingerprint > 0 && first.customGlowIsCustom === true && first.customGlowParamKeys === 'intensity|threshold' && Math.abs(Number(first.customGlowIntensity) - 0.5) < 1e-3 && Math.abs(Number(first.customGlowThreshold) - 0.2) < 1e-3 && first.mutationDelta === 10 && first.lastReasonCode === 'postfx_ok' && first.lastOk === true; })()",
1424
+ },
1425
+ {
1426
+ id: 'draw3d.postfx.reason-codes.stable',
1427
+ expression: "(() => { const reasonOf = (entry) => (entry && entry.reasonCode) || null; const collect = () => { aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('custom:glow'); const invalidPassEmpty = aura.draw3d.setPostFXPass('', {}); const invalidPassType = aura.draw3d.setPostFXPass(42, {}); const unsupportedPass = aura.draw3d.setPostFXPass('ssao', {}); const invalidOptions = aura.draw3d.setPostFXPass('bloom', 'bad'); const invalidTargetChain = aura.draw3d.setPostFXPass('bloom', { targetChain: 'bad' }); const invalidIntermediateTargetType = aura.draw3d.setPostFXPass('bloom', { targetChain: { intermediateTargets: 'bad' } }); const invalidIntermediateTargetEntry = aura.draw3d.setPostFXPass('bloom', { targetChain: { intermediateTargets: ['ok', 'bad!'] } }); const invalidComposeMode = aura.draw3d.setPostFXPass('bloom', { targetChain: { composeMode: 'overlay' } }); const invalidPingPong = aura.draw3d.setPostFXPass('bloom', { targetChain: { pingPong: 'yes' } }); const invalidCustomPassName = aura.draw3d.setPostFXPass('custom:bad name', {}); const invalidCustomParams = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 'high' } }); const unsupportedCustomParams = aura.draw3d.setPostFXPass('bloom', { customParams: { intensity: 1 } }); const configured = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 0.25 } }); const invalidEnabled = aura.draw3d.setPostFXEnabled('custom:glow', 'yes'); const removeConfigured = aura.draw3d.removePostFXPass('custom:glow'); const missingToggle = aura.draw3d.setPostFXEnabled('custom:glow', true); const missingRemove = aura.draw3d.removePostFXPass('custom:glow'); return { invalidPassEmpty: reasonOf(invalidPassEmpty), invalidPassType: reasonOf(invalidPassType), unsupportedPass: reasonOf(unsupportedPass), invalidOptions: reasonOf(invalidOptions), invalidTargetChain: reasonOf(invalidTargetChain), invalidIntermediateTargetType: reasonOf(invalidIntermediateTargetType), invalidIntermediateTargetEntry: reasonOf(invalidIntermediateTargetEntry), invalidComposeMode: reasonOf(invalidComposeMode), invalidPingPong: reasonOf(invalidPingPong), invalidCustomPassName: reasonOf(invalidCustomPassName), invalidCustomParams: reasonOf(invalidCustomParams), unsupportedCustomParams: reasonOf(unsupportedCustomParams), configuredOk: !!configured && configured.ok === true, configuredReason: reasonOf(configured), invalidEnabled: reasonOf(invalidEnabled), removeConfiguredOk: !!removeConfigured && removeConfigured.ok === true, removeConfiguredReason: reasonOf(removeConfigured), missingToggle: reasonOf(missingToggle), missingRemove: reasonOf(missingRemove) }; }; const first = collect(); const second = collect(); return JSON.stringify(first) === JSON.stringify(second) && first.invalidPassEmpty === 'postfx_invalid_pass_name' && first.invalidPassType === 'postfx_invalid_pass_name' && first.unsupportedPass === 'postfx_pass_unsupported' && first.invalidOptions === 'postfx_invalid_options' && first.invalidTargetChain === 'postfx_invalid_target_chain' && first.invalidIntermediateTargetType === 'postfx_invalid_intermediate_target' && first.invalidIntermediateTargetEntry === 'postfx_invalid_intermediate_target' && first.invalidComposeMode === 'postfx_invalid_compose_mode' && first.invalidPingPong === 'postfx_invalid_ping_pong' && first.invalidCustomPassName === 'postfx_invalid_custom_pass_name' && first.invalidCustomParams === 'postfx_invalid_custom_params' && first.unsupportedCustomParams === 'postfx_custom_param_unsupported' && first.configuredOk === true && first.configuredReason === 'postfx_ok' && first.invalidEnabled === 'postfx_invalid_enabled' && first.removeConfiguredOk === true && first.removeConfiguredReason === 'postfx_ok' && first.missingToggle === 'postfx_pass_missing' && first.missingRemove === 'postfx_pass_missing'; })()",
1408
1428
  },
1409
1429
  ],
1410
1430
  source: `
@@ -2261,7 +2281,7 @@ export const DEFAULT_CONFORMANCE_CASES = [
2261
2281
  },
2262
2282
  {
2263
2283
  id: 'draw3d.postfx.reason-codes.stable',
2264
- expression: "(() => { const reasonOf = (entry) => (entry && entry.reasonCode) || null; const collect = () => { aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('fxaa'); const invalidPassEmpty = aura.draw3d.setPostFXPass('', {}); const invalidPassType = aura.draw3d.setPostFXPass(42, {}); const unsupportedPass = aura.draw3d.setPostFXPass('ssao', {}); const invalidOptions = aura.draw3d.setPostFXPass('bloom', 'bad'); const configured = aura.draw3d.setPostFXPass('bloom', { strength: 1.0 }); const invalidEnabled = aura.draw3d.setPostFXEnabled('bloom', 'yes'); const removeConfigured = aura.draw3d.removePostFXPass('bloom'); const missingToggle = aura.draw3d.setPostFXEnabled('fxaa', true); const missingRemove = aura.draw3d.removePostFXPass('fxaa'); return { invalidPassEmpty: reasonOf(invalidPassEmpty), invalidPassType: reasonOf(invalidPassType), unsupportedPass: reasonOf(unsupportedPass), invalidOptions: reasonOf(invalidOptions), configuredOk: !!configured && configured.ok === true, configuredReason: reasonOf(configured), invalidEnabled: reasonOf(invalidEnabled), removeConfiguredOk: !!removeConfigured && removeConfigured.ok === true, removeConfiguredReason: reasonOf(removeConfigured), missingToggle: reasonOf(missingToggle), missingRemove: reasonOf(missingRemove) }; }; const first = collect(); const second = collect(); const invalidPassEmptyOk = first.invalidPassEmpty === 'postfx_invalid_pass_name' || first.invalidPassEmpty === 'postfx_pass_unsupported'; const invalidPassTypeOk = first.invalidPassType === 'postfx_invalid_pass_name' || first.invalidPassType === 'postfx_pass_unsupported'; return JSON.stringify(first) === JSON.stringify(second) && invalidPassEmptyOk && invalidPassTypeOk && first.unsupportedPass === 'postfx_pass_unsupported' && first.invalidOptions === 'postfx_invalid_options' && first.configuredOk === true && first.configuredReason === 'postfx_ok' && first.invalidEnabled === 'postfx_invalid_enabled' && first.removeConfiguredOk === true && first.removeConfiguredReason === 'postfx_ok' && first.missingToggle === 'postfx_pass_missing' && first.missingRemove === 'postfx_pass_missing'; })()",
2284
+ expression: "(() => { const reasonOf = (entry) => (entry && entry.reasonCode) || null; const collect = () => { aura.draw3d.removePostFXPass('bloom'); aura.draw3d.removePostFXPass('custom:glow'); const invalidPassEmpty = aura.draw3d.setPostFXPass('', {}); const invalidPassType = aura.draw3d.setPostFXPass(42, {}); const unsupportedPass = aura.draw3d.setPostFXPass('ssao', {}); const invalidOptions = aura.draw3d.setPostFXPass('bloom', 'bad'); const invalidTargetChain = aura.draw3d.setPostFXPass('bloom', { targetChain: 'bad' }); const invalidIntermediateTargetType = aura.draw3d.setPostFXPass('bloom', { targetChain: { intermediateTargets: 'bad' } }); const invalidIntermediateTargetEntry = aura.draw3d.setPostFXPass('bloom', { targetChain: { intermediateTargets: ['ok', 'bad!'] } }); const invalidComposeMode = aura.draw3d.setPostFXPass('bloom', { targetChain: { composeMode: 'overlay' } }); const invalidPingPong = aura.draw3d.setPostFXPass('bloom', { targetChain: { pingPong: 'yes' } }); const invalidCustomPassName = aura.draw3d.setPostFXPass('custom:bad name', {}); const invalidCustomParams = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 'high' } }); const unsupportedCustomParams = aura.draw3d.setPostFXPass('bloom', { customParams: { intensity: 1 } }); const configured = aura.draw3d.setPostFXPass('custom:glow', { customParams: { intensity: 0.25 } }); const invalidEnabled = aura.draw3d.setPostFXEnabled('custom:glow', 'yes'); const removeConfigured = aura.draw3d.removePostFXPass('custom:glow'); const missingToggle = aura.draw3d.setPostFXEnabled('custom:glow', true); const missingRemove = aura.draw3d.removePostFXPass('custom:glow'); return { invalidPassEmpty: reasonOf(invalidPassEmpty), invalidPassType: reasonOf(invalidPassType), unsupportedPass: reasonOf(unsupportedPass), invalidOptions: reasonOf(invalidOptions), invalidTargetChain: reasonOf(invalidTargetChain), invalidIntermediateTargetType: reasonOf(invalidIntermediateTargetType), invalidIntermediateTargetEntry: reasonOf(invalidIntermediateTargetEntry), invalidComposeMode: reasonOf(invalidComposeMode), invalidPingPong: reasonOf(invalidPingPong), invalidCustomPassName: reasonOf(invalidCustomPassName), invalidCustomParams: reasonOf(invalidCustomParams), unsupportedCustomParams: reasonOf(unsupportedCustomParams), configuredOk: !!configured && configured.ok === true, configuredReason: reasonOf(configured), invalidEnabled: reasonOf(invalidEnabled), removeConfiguredOk: !!removeConfigured && removeConfigured.ok === true, removeConfiguredReason: reasonOf(removeConfigured), missingToggle: reasonOf(missingToggle), missingRemove: reasonOf(missingRemove) }; }; const first = collect(); const second = collect(); return JSON.stringify(first) === JSON.stringify(second) && first.invalidPassEmpty === 'postfx_invalid_pass_name' && first.invalidPassType === 'postfx_invalid_pass_name' && first.unsupportedPass === 'postfx_pass_unsupported' && first.invalidOptions === 'postfx_invalid_options' && first.invalidTargetChain === 'postfx_invalid_target_chain' && first.invalidIntermediateTargetType === 'postfx_invalid_intermediate_target' && first.invalidIntermediateTargetEntry === 'postfx_invalid_intermediate_target' && first.invalidComposeMode === 'postfx_invalid_compose_mode' && first.invalidPingPong === 'postfx_invalid_ping_pong' && first.invalidCustomPassName === 'postfx_invalid_custom_pass_name' && first.invalidCustomParams === 'postfx_invalid_custom_params' && first.unsupportedCustomParams === 'postfx_custom_param_unsupported' && first.configuredOk === true && first.configuredReason === 'postfx_ok' && first.invalidEnabled === 'postfx_invalid_enabled' && first.removeConfiguredOk === true && first.removeConfiguredReason === 'postfx_ok' && first.missingToggle === 'postfx_pass_missing' && first.missingRemove === 'postfx_pass_missing'; })()",
2265
2285
  },
2266
2286
  ],
2267
2287
  source: `
@@ -2356,6 +2376,10 @@ export const DEFAULT_CONFORMANCE_CASES = [
2356
2376
  id: 'tilemap.import.draw.layer-order.deterministic',
2357
2377
  expression: "(() => { const fixture = { width: 8, height: 8, tilewidth: 16, tileheight: 16, properties: [{ name: 'theme', type: 'string', value: 'forest' }], layers: [ { name: 'ground', type: 'tilelayer', width: 8, height: 8, properties: [{ name: 'solid', type: 'bool', value: true }], data: Array.from({ length: 64 }, () => 1) }, { name: 'spawn', type: 'objectgroup', properties: [{ name: 'kind', type: 'string', value: 'spawns' }], objects: [ { id: 10, name: 'hero', x: 16, y: 16, width: 16, height: 16, properties: [{ name: 'faction', type: 'string', value: 'player' }] }, { id: 11, name: 'loot', x: 32, y: 32, point: true, properties: { rarity: 'common', value: 1 } } ] }, { name: 'decor', type: 'tilelayer', width: 8, height: 8, data: Array.from({ length: 64 }, (_, i) => (i % 5 === 0 ? 1 : 0)) } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1, properties: [{ name: 'atlas', value: 'base' }] } ] }; const mapId = aura.tilemap.import(fixture); const first = aura.tilemap.draw(mapId, { camera: { x: 0, y: 0, width: 32, height: 32 } }); const second = aura.tilemap.draw(mapId, { camera: { x: 0, y: 0, width: 32, height: 32 } }); const info = aura.tilemap.getInfo(mapId); aura.tilemap.unload(mapId); return !!info && info.layerCount === 2 && info.objectLayerCount === 1 && info.objectCount === 2 && info.mapPropertyCount === 1 && first && second && first.layerOrder.join(',') === 'ground,decor' && JSON.stringify(first.layerOrder) === JSON.stringify(second.layerOrder) && first.drawnTiles === second.drawnTiles; })()",
2358
2378
  },
2379
+ {
2380
+ id: 'tilemap.import.expanded-schema.acceptance.deterministic',
2381
+ expression: "(() => { const runSample = () => { const fixture = { width: 4, height: 4, tilewidth: 16, tileheight: 16, properties: { difficulty: 'hard', seed: 7 }, solidLayerNames: ['collision'], layers: [ { name: 'ground', type: 'tilelayer', width: 4, height: 4, offsetx: 2, offsety: 4, data: Array.from({ length: 16 }, () => 1), properties: { solid: true } }, { name: 'collision', type: 'tilelayer', width: 4, height: 4, data: [0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], properties: [{ name: 'solid', value: true }] }, { name: 'objects', type: 'objectgroup', draworder: 'index', objects: [ { id: 1, name: 'rect', x: 0, y: 0, width: 16, height: 16, properties: { loot: false } }, { id: 2, name: 'point', x: 16, y: 16, point: true, properties: [{ name: 'kind', value: 'spawn' }] }, { id: 3, name: 'ellipse', x: 32, y: 16, width: 16, height: 8, ellipse: true }, { id: 4, name: 'poly', x: 48, y: 16, polygon: [{ x: 0, y: 0 }, { x: 8, y: 0 }, { x: 8, y: 8 }] }, { id: 5, name: 'path', x: 48, y: 32, polyline: [{ x: 0, y: 0 }, { x: 8, y: 8 }] }, { id: 6, name: 'tileobj', x: 0, y: 32, gid: 5, width: 16, height: 16 } ] } ], tilesets: [ { firstgid: 1, image: 'tiles_a.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1, margin: 1, spacing: 0, properties: { atlas: 'a' } }, { firstgid: 5, image: 'tiles_b.png', tilewidth: 16, tileheight: 16, tilecount: 2, columns: 1, margin: 0, spacing: 1, properties: [{ name: 'atlas', value: 'b' }] } ] }; const mapId = aura.tilemap.import(fixture); const info = aura.tilemap.getInfo(mapId); const draw = aura.tilemap.draw(mapId, { cull: false }); const ground = aura.tilemap.drawLayer(mapId, 'ground', { cull: false }); const unload = aura.tilemap.unload(mapId); return { layerCount: Number(info?.layerCount || 0), objectLayerCount: Number(info?.objectLayerCount || 0), objectCount: Number(info?.objectCount || 0), tilesetCount: Number(info?.tilesetCount || 0), mapPropertyCount: Number(info?.mapPropertyCount || 0), layerOrder: Array.isArray(draw?.layerOrder) ? draw.layerOrder.join(',') : '', drawnTiles: Number(draw?.drawnTiles || 0), groundDrawnTiles: Number(ground?.drawnTiles || 0), unload }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.layerCount === 2 && first.objectLayerCount === 1 && first.objectCount === 6 && first.tilesetCount === 2 && first.mapPropertyCount === 2 && first.layerOrder === 'ground,collision' && first.drawnTiles === 17 && first.groundDrawnTiles === 16 && first.unload === true; })()",
2382
+ },
2359
2383
  {
2360
2384
  id: 'tilemap.culling.reduces-draw-submissions',
2361
2385
  expression: "(() => { const size = 32; const fixture = { width: size, height: size, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: size, height: size, data: Array.from({ length: size * size }, () => 1) } ], tilesets: [ { firstgid: 1, image: 'tiles.png', tilewidth: 16, tileheight: 16, tilecount: 1, columns: 1 } ] }; const mapId = aura.tilemap.import(fixture); const full = aura.tilemap.drawLayer(mapId, 'ground', { cull: false }); const culled = aura.tilemap.drawLayer(mapId, 'ground', { camera: { x: 0, y: 0, width: 64, height: 64 } }); aura.tilemap.unload(mapId); return !!full && !!culled && full.drawnTiles === (size * size) && culled.drawnTiles < full.drawnTiles && culled.culledTiles > 0; })()",
@@ -2368,6 +2392,10 @@ export const DEFAULT_CONFORMANCE_CASES = [
2368
2392
  id: 'tilemap.import.invalid-object-property.reason-code',
2369
2393
  expression: "(() => { try { aura.tilemap.import({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] }, { name: 'objects', type: 'objectgroup', objects: [ { id: 1, x: 0, y: 0, properties: [ { name: 'bad', value: { nested: true } } ] } ] } ], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }); return false; } catch (e) { return String(e).includes('aura.tilemap.import: invalid-property-value'); } })()",
2370
2394
  },
2395
+ {
2396
+ id: 'tilemap.import.expanded-schema.rejection.reason-codes',
2397
+ expression: "(() => { const runSample = () => { const expectImportFailure = (factory, reasonCode) => { try { aura.tilemap.import(factory()); return false; } catch (err) { return String(err).includes('aura.tilemap.import: ' + reasonCode); } }; return { compression: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [{ name: 'ground', type: 'tilelayer', width: 2, height: 2, compression: 'zlib', data: [1, 1, 1, 1] }], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'unsupported-layer-compression'), encoding: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [{ name: 'ground', type: 'tilelayer', width: 2, height: 2, encoding: 'base64', data: [1, 1, 1, 1] }], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'unsupported-layer-encoding'), invalidObjectShape: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] }, { name: 'objects', type: 'objectgroup', objects: [ { id: 1, x: 0, y: 0, polygon: [{ x: 0, y: 0 }, { x: 1, y: 0 }], polyline: [{ x: 0, y: 0 }, { x: 1, y: 1 }] } ] } ], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'invalid-object-shape'), unmappedObjectGid: expectImportFailure(() => ({ width: 2, height: 2, tilewidth: 16, tileheight: 16, layers: [ { name: 'ground', type: 'tilelayer', width: 2, height: 2, data: [1, 1, 1, 1] }, { name: 'objects', type: 'objectgroup', objects: [ { id: 1, x: 0, y: 0, gid: 99 } ] } ], tilesets: [{ firstgid: 1, image: 'tiles.png', columns: 1, tilecount: 1 }] }), 'unmapped-object-gid') }; }; const first = runSample(); const second = runSample(); return JSON.stringify(first) === JSON.stringify(second) && first.compression === true && first.encoding === true && first.invalidObjectShape === true && first.unmappedObjectGid === true; })()",
2398
+ },
2371
2399
  ],
2372
2400
  source: `
2373
2401
  let tilemapId = 0;
@@ -4116,6 +4144,14 @@ function normalizeRuntimeInspectorScene3dRuntime(scene3dRuntime) {
4116
4144
  postfxPassCount: numericOr(scene3dRuntime?.submission?.postfxPassCount),
4117
4145
  postfxEnabledPassCount: numericOr(scene3dRuntime?.submission?.postfxEnabledPassCount),
4118
4146
  postfxOrderFingerprint: numericOr(scene3dRuntime?.submission?.postfxOrderFingerprint),
4147
+ postfxTargetChainFingerprint: numericOr(scene3dRuntime?.submission?.postfxTargetChainFingerprint),
4148
+ postfxCustomParamFingerprint: numericOr(scene3dRuntime?.submission?.postfxCustomParamFingerprint),
4149
+ postfxIntermediateTargetCount: numericOr(scene3dRuntime?.submission?.postfxIntermediateTargetCount),
4150
+ postfxPingPongEnabled: scene3dRuntime?.submission?.postfxPingPongEnabled === true,
4151
+ postfxComposeMode: typeof scene3dRuntime?.submission?.postfxComposeMode === 'string'
4152
+ ? scene3dRuntime.submission.postfxComposeMode
4153
+ : 'replace',
4154
+ postfxCustomPassCount: numericOr(scene3dRuntime?.submission?.postfxCustomPassCount),
4119
4155
  postfxMutationCount: numericOr(scene3dRuntime?.submission?.postfxMutationCount),
4120
4156
  postfxLastOperation: typeof scene3dRuntime?.submission?.postfxLastOperation === 'string'
4121
4157
  ? scene3dRuntime.submission.postfxLastOperation
@@ -4713,6 +4749,14 @@ function buildNativeProbeSource(conformanceCase, options = {}) {
4713
4749
  postfxPassCount: __num(scene3dSubmission.postfxPassCount),
4714
4750
  postfxEnabledPassCount: __num(scene3dSubmission.postfxEnabledPassCount),
4715
4751
  postfxOrderFingerprint: __num(scene3dSubmission.postfxOrderFingerprint),
4752
+ postfxTargetChainFingerprint: __num(scene3dSubmission.postfxTargetChainFingerprint),
4753
+ postfxCustomParamFingerprint: __num(scene3dSubmission.postfxCustomParamFingerprint),
4754
+ postfxIntermediateTargetCount: __num(scene3dSubmission.postfxIntermediateTargetCount),
4755
+ postfxPingPongEnabled: scene3dSubmission.postfxPingPongEnabled === true,
4756
+ postfxComposeMode: typeof scene3dSubmission.postfxComposeMode === 'string'
4757
+ ? scene3dSubmission.postfxComposeMode
4758
+ : 'replace',
4759
+ postfxCustomPassCount: __num(scene3dSubmission.postfxCustomPassCount),
4716
4760
  postfxMutationCount: __num(scene3dSubmission.postfxMutationCount),
4717
4761
  postfxLastOperation: typeof scene3dSubmission.postfxLastOperation === 'string'
4718
4762
  ? scene3dSubmission.postfxLastOperation
@@ -5184,7 +5228,7 @@ export async function runConformanceSuite(options = {}) {
5184
5228
  entryRelative: nativeEntryRelative,
5185
5229
  timeoutMs: nativeTimeoutMs,
5186
5230
  nativeEnv: {
5187
- AURA_HEADLESS: '1',
5231
+ AURA_WINDOW_HIDDEN: '1',
5188
5232
  ...(options.nativeEnv || {}),
5189
5233
  ...((conformanceCase && conformanceCase.nativeEnv) || {}),
5190
5234
  },