@aura3d/cli 3.0.1 → 4.0.0
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 +2 -2
- package/dist/admission/artDirection.d.ts +28 -0
- package/dist/admission/artDirection.d.ts.map +1 -0
- package/dist/admission/artDirection.js +47 -0
- package/dist/admission/artDirection.js.map +1 -0
- package/dist/admission/audio.d.ts +19 -0
- package/dist/admission/audio.d.ts.map +1 -0
- package/dist/admission/audio.js +31 -0
- package/dist/admission/audio.js.map +1 -0
- package/dist/admission/builder-patterns.d.ts +25 -0
- package/dist/admission/builder-patterns.d.ts.map +1 -0
- package/dist/admission/builder-patterns.js +40 -0
- package/dist/admission/builder-patterns.js.map +1 -0
- package/dist/admission/gates.d.ts +136 -0
- package/dist/admission/gates.d.ts.map +1 -0
- package/dist/admission/gates.js +335 -0
- package/dist/admission/gates.js.map +1 -0
- package/dist/admission/glb.d.ts +64 -0
- package/dist/admission/glb.d.ts.map +1 -0
- package/dist/admission/glb.js +128 -0
- package/dist/admission/glb.js.map +1 -0
- package/dist/admission/index.d.ts +8 -0
- package/dist/admission/index.d.ts.map +1 -0
- package/dist/admission/index.js +8 -0
- package/dist/admission/index.js.map +1 -0
- package/dist/admission/profiles.d.ts +52 -0
- package/dist/admission/profiles.d.ts.map +1 -0
- package/dist/admission/profiles.js +91 -0
- package/dist/admission/profiles.js.map +1 -0
- package/dist/admission/qrFlags.d.ts +12 -0
- package/dist/admission/qrFlags.d.ts.map +1 -0
- package/dist/admission/qrFlags.js +48 -0
- package/dist/admission/qrFlags.js.map +1 -0
- package/dist/admission/routeGates.d.ts +36 -0
- package/dist/admission/routeGates.d.ts.map +1 -0
- package/dist/admission/routeGates.js +144 -0
- package/dist/admission/routeGates.js.map +1 -0
- package/dist/admission/texel.d.ts +50 -0
- package/dist/admission/texel.d.ts.map +1 -0
- package/dist/admission/texel.js +177 -0
- package/dist/admission/texel.js.map +1 -0
- package/dist/admission/textureStats.d.ts +45 -0
- package/dist/admission/textureStats.d.ts.map +1 -0
- package/dist/admission/textureStats.js +201 -0
- package/dist/admission/textureStats.js.map +1 -0
- package/dist/animation-asset-validator.d.ts +44 -0
- package/dist/animation-asset-validator.d.ts.map +1 -1
- package/dist/animation-asset-validator.js +80 -1
- package/dist/animation-asset-validator.js.map +1 -1
- package/dist/asset-core-types.d.ts +99 -4
- package/dist/asset-core-types.d.ts.map +1 -1
- package/dist/asset-inspection-types.d.ts +8 -0
- package/dist/asset-inspection-types.d.ts.map +1 -1
- package/dist/asset-manifest.d.ts +1 -0
- package/dist/asset-manifest.d.ts.map +1 -1
- package/dist/asset-manifest.js +13 -4
- package/dist/asset-manifest.js.map +1 -1
- package/dist/asset-route-typegen.d.ts +37 -0
- package/dist/asset-route-typegen.d.ts.map +1 -0
- package/dist/asset-route-typegen.js +179 -0
- package/dist/asset-route-typegen.js.map +1 -0
- package/dist/cli-help.d.ts +1 -1
- package/dist/cli-help.d.ts.map +1 -1
- package/dist/cli-help.js +9 -4
- package/dist/cli-help.js.map +1 -1
- package/dist/cli-options.d.ts +7 -0
- package/dist/cli-options.d.ts.map +1 -1
- package/dist/cli-options.js +33 -2
- package/dist/cli-options.js.map +1 -1
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +126 -11
- package/dist/cli.js.map +1 -1
- package/dist/codemods/engine-entry-imports.d.ts +22 -0
- package/dist/codemods/engine-entry-imports.d.ts.map +1 -0
- package/dist/codemods/engine-entry-imports.js +159 -0
- package/dist/codemods/engine-entry-imports.js.map +1 -0
- package/dist/codemods/lean-imports.d.ts +40 -0
- package/dist/codemods/lean-imports.d.ts.map +1 -0
- package/dist/codemods/lean-imports.js +175 -0
- package/dist/codemods/lean-imports.js.map +1 -0
- package/dist/codemods/renderer-imports.d.ts +36 -0
- package/dist/codemods/renderer-imports.d.ts.map +1 -0
- package/dist/codemods/renderer-imports.js +364 -0
- package/dist/codemods/renderer-imports.js.map +1 -0
- package/dist/codemods/renderer-mode.d.ts +38 -0
- package/dist/codemods/renderer-mode.d.ts.map +1 -0
- package/dist/codemods/renderer-mode.js +130 -0
- package/dist/codemods/renderer-mode.js.map +1 -0
- package/dist/commands/prd01/index.d.ts +8 -0
- package/dist/commands/prd01/index.d.ts.map +1 -0
- package/dist/commands/prd01/index.js +39 -0
- package/dist/commands/prd01/index.js.map +1 -0
- package/dist/commands/prd02/environmentsBake.d.ts +6 -0
- package/dist/commands/prd02/environmentsBake.d.ts.map +1 -0
- package/dist/commands/prd02/environmentsBake.js +174 -0
- package/dist/commands/prd02/environmentsBake.js.map +1 -0
- package/dist/commands/prd02/index.d.ts +2 -0
- package/dist/commands/prd02/index.d.ts.map +1 -0
- package/dist/commands/prd02/index.js +26 -0
- package/dist/commands/prd02/index.js.map +1 -0
- package/dist/commands/prd02/migrateLighting.d.ts +17 -0
- package/dist/commands/prd02/migrateLighting.d.ts.map +1 -0
- package/dist/commands/prd02/migrateLighting.js +86 -0
- package/dist/commands/prd02/migrateLighting.js.map +1 -0
- package/dist/commands/prd02/migrateLightingSweep.d.ts +20 -0
- package/dist/commands/prd02/migrateLightingSweep.d.ts.map +1 -0
- package/dist/commands/prd02/migrateLightingSweep.js +105 -0
- package/dist/commands/prd02/migrateLightingSweep.js.map +1 -0
- package/dist/commands/prd03/index.d.ts +7 -0
- package/dist/commands/prd03/index.d.ts.map +1 -0
- package/dist/commands/prd03/index.js +9 -0
- package/dist/commands/prd03/index.js.map +1 -0
- package/dist/commands/prd04/index.d.ts +10 -0
- package/dist/commands/prd04/index.d.ts.map +1 -0
- package/dist/commands/prd04/index.js +10 -0
- package/dist/commands/prd04/index.js.map +1 -0
- package/dist/commands/prd04/modelTintReport.d.ts +16 -0
- package/dist/commands/prd04/modelTintReport.d.ts.map +1 -0
- package/dist/commands/prd04/modelTintReport.js +114 -0
- package/dist/commands/prd04/modelTintReport.js.map +1 -0
- package/dist/commands/prd04/pinEmissiveDefaults.d.ts +3 -0
- package/dist/commands/prd04/pinEmissiveDefaults.d.ts.map +1 -0
- package/dist/commands/prd04/pinEmissiveDefaults.js +36 -0
- package/dist/commands/prd04/pinEmissiveDefaults.js.map +1 -0
- package/dist/commands/prd05/admit.d.ts +54 -0
- package/dist/commands/prd05/admit.d.ts.map +1 -0
- package/dist/commands/prd05/admit.js +153 -0
- package/dist/commands/prd05/admit.js.map +1 -0
- package/dist/commands/prd05/codemods/assetsRouteModules.d.ts +3 -0
- package/dist/commands/prd05/codemods/assetsRouteModules.d.ts.map +1 -0
- package/dist/commands/prd05/codemods/assetsRouteModules.js +92 -0
- package/dist/commands/prd05/codemods/assetsRouteModules.js.map +1 -0
- package/dist/commands/prd05/index.d.ts +9 -0
- package/dist/commands/prd05/index.d.ts.map +1 -0
- package/dist/commands/prd05/index.js +171 -0
- package/dist/commands/prd05/index.js.map +1 -0
- package/dist/commands/prd05/library.d.ts +23 -0
- package/dist/commands/prd05/library.d.ts.map +1 -0
- package/dist/commands/prd05/library.js +245 -0
- package/dist/commands/prd05/library.js.map +1 -0
- package/dist/commands/prd05/lookdev.d.ts +14 -0
- package/dist/commands/prd05/lookdev.d.ts.map +1 -0
- package/dist/commands/prd05/lookdev.js +68 -0
- package/dist/commands/prd05/lookdev.js.map +1 -0
- package/dist/commands/prd05/optimize.d.ts +16 -0
- package/dist/commands/prd05/optimize.d.ts.map +1 -0
- package/dist/commands/prd05/optimize.js +55 -0
- package/dist/commands/prd05/optimize.js.map +1 -0
- package/dist/commands/prd05/prune.d.ts +26 -0
- package/dist/commands/prd05/prune.d.ts.map +1 -0
- package/dist/commands/prd05/prune.js +104 -0
- package/dist/commands/prd05/prune.js.map +1 -0
- package/dist/commands/prd05/review.d.ts +24 -0
- package/dist/commands/prd05/review.d.ts.map +1 -0
- package/dist/commands/prd05/review.js +40 -0
- package/dist/commands/prd05/review.js.map +1 -0
- package/dist/commands/prd06/index.d.ts +6 -0
- package/dist/commands/prd06/index.d.ts.map +1 -0
- package/dist/commands/prd06/index.js +86 -0
- package/dist/commands/prd06/index.js.map +1 -0
- package/dist/commands/prd06/inspectAnimationClips.d.ts +86 -0
- package/dist/commands/prd06/inspectAnimationClips.d.ts.map +1 -0
- package/dist/commands/prd06/inspectAnimationClips.js +168 -0
- package/dist/commands/prd06/inspectAnimationClips.js.map +1 -0
- package/dist/commands/prd06/validateHero.d.ts +18 -0
- package/dist/commands/prd06/validateHero.d.ts.map +1 -0
- package/dist/commands/prd06/validateHero.js +91 -0
- package/dist/commands/prd06/validateHero.js.map +1 -0
- package/dist/commands/prd07/codemods.d.ts +28 -0
- package/dist/commands/prd07/codemods.d.ts.map +1 -0
- package/dist/commands/prd07/codemods.js +155 -0
- package/dist/commands/prd07/codemods.js.map +1 -0
- package/dist/commands/prd07/index.d.ts +2 -0
- package/dist/commands/prd07/index.d.ts.map +1 -0
- package/dist/commands/prd07/index.js +151 -0
- package/dist/commands/prd07/index.js.map +1 -0
- package/dist/commands/prd08/feelLint.d.ts +13 -0
- package/dist/commands/prd08/feelLint.d.ts.map +1 -0
- package/dist/commands/prd08/feelLint.js +32 -0
- package/dist/commands/prd08/feelLint.js.map +1 -0
- package/dist/commands/prd08/index.d.ts +2 -0
- package/dist/commands/prd08/index.d.ts.map +1 -0
- package/dist/commands/prd08/index.js +16 -0
- package/dist/commands/prd08/index.js.map +1 -0
- package/dist/commands/prd08/motionReport.d.ts +94 -0
- package/dist/commands/prd08/motionReport.d.ts.map +1 -0
- package/dist/commands/prd08/motionReport.js +197 -0
- package/dist/commands/prd08/motionReport.js.map +1 -0
- package/dist/commands/prd09/codemods/audio-wrapper.d.ts +9 -0
- package/dist/commands/prd09/codemods/audio-wrapper.d.ts.map +1 -0
- package/dist/commands/prd09/codemods/audio-wrapper.js +30 -0
- package/dist/commands/prd09/codemods/audio-wrapper.js.map +1 -0
- package/dist/commands/prd09/codemods/capture-branches.d.ts +10 -0
- package/dist/commands/prd09/codemods/capture-branches.d.ts.map +1 -0
- package/dist/commands/prd09/codemods/capture-branches.js +54 -0
- package/dist/commands/prd09/codemods/capture-branches.js.map +1 -0
- package/dist/commands/prd09/codemods/evidence-globals.d.ts +8 -0
- package/dist/commands/prd09/codemods/evidence-globals.d.ts.map +1 -0
- package/dist/commands/prd09/codemods/evidence-globals.js +19 -0
- package/dist/commands/prd09/codemods/evidence-globals.js.map +1 -0
- package/dist/commands/prd09/codemods/perf-script.d.ts +8 -0
- package/dist/commands/prd09/codemods/perf-script.d.ts.map +1 -0
- package/dist/commands/prd09/codemods/perf-script.js +24 -0
- package/dist/commands/prd09/codemods/perf-script.js.map +1 -0
- package/dist/commands/prd09/index.d.ts +8 -0
- package/dist/commands/prd09/index.d.ts.map +1 -0
- package/dist/commands/prd09/index.js +19 -0
- package/dist/commands/prd09/index.js.map +1 -0
- package/dist/commands/prd09/perf-report.d.ts +56 -0
- package/dist/commands/prd09/perf-report.d.ts.map +1 -0
- package/dist/commands/prd09/perf-report.js +118 -0
- package/dist/commands/prd09/perf-report.js.map +1 -0
- package/dist/commands/prd09/sfx-admit.d.ts +18 -0
- package/dist/commands/prd09/sfx-admit.d.ts.map +1 -0
- package/dist/commands/prd09/sfx-admit.js +120 -0
- package/dist/commands/prd09/sfx-admit.js.map +1 -0
- package/dist/commands/prd10/index.d.ts +2 -0
- package/dist/commands/prd10/index.d.ts.map +1 -0
- package/dist/commands/prd10/index.js +109 -0
- package/dist/commands/prd10/index.js.map +1 -0
- package/dist/commands/prd11/batchOptout.d.ts +35 -0
- package/dist/commands/prd11/batchOptout.d.ts.map +1 -0
- package/dist/commands/prd11/batchOptout.js +155 -0
- package/dist/commands/prd11/batchOptout.js.map +1 -0
- package/dist/commands/prd11/index.d.ts +2 -0
- package/dist/commands/prd11/index.d.ts.map +1 -0
- package/dist/commands/prd11/index.js +13 -0
- package/dist/commands/prd11/index.js.map +1 -0
- package/dist/commands/prd11/perfGate.d.ts +15 -0
- package/dist/commands/prd11/perfGate.d.ts.map +1 -0
- package/dist/commands/prd11/perfGate.js +98 -0
- package/dist/commands/prd11/perfGate.js.map +1 -0
- package/dist/commands/prd13/index.d.ts +15 -0
- package/dist/commands/prd13/index.d.ts.map +1 -0
- package/dist/commands/prd13/index.js +26 -0
- package/dist/commands/prd13/index.js.map +1 -0
- package/dist/commands/prd13/run.d.ts +10 -0
- package/dist/commands/prd13/run.d.ts.map +1 -0
- package/dist/commands/prd13/run.js +29 -0
- package/dist/commands/prd13/run.js.map +1 -0
- package/dist/commands/prd14/index.d.ts +6 -0
- package/dist/commands/prd14/index.d.ts.map +1 -0
- package/dist/commands/prd14/index.js +6 -0
- package/dist/commands/prd14/index.js.map +1 -0
- package/dist/commands/prd15/index.d.ts +8 -0
- package/dist/commands/prd15/index.d.ts.map +1 -0
- package/dist/commands/prd15/index.js +152 -0
- package/dist/commands/prd15/index.js.map +1 -0
- package/dist/commands/registry.d.ts +19 -0
- package/dist/commands/registry.d.ts.map +1 -0
- package/dist/commands/registry.js +19 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/contracts/assetManifest.d.ts +80 -0
- package/dist/contracts/assetManifest.d.ts.map +1 -0
- package/dist/contracts/assetManifest.js +9 -0
- package/dist/contracts/assetManifest.js.map +1 -0
- package/dist/contracts/commands.d.ts +53 -0
- package/dist/contracts/commands.d.ts.map +1 -0
- package/dist/contracts/commands.js +37 -0
- package/dist/contracts/commands.js.map +1 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +271 -71
- package/dist/index.js.map +1 -1
- package/dist/library-manifest.d.ts +86 -0
- package/dist/library-manifest.d.ts.map +1 -0
- package/dist/library-manifest.js +95 -0
- package/dist/library-manifest.js.map +1 -0
- package/dist/look/capture.d.ts +51 -0
- package/dist/look/capture.d.ts.map +1 -0
- package/dist/look/capture.js +229 -0
- package/dist/look/capture.js.map +1 -0
- package/dist/look/judge.d.ts +24 -0
- package/dist/look/judge.d.ts.map +1 -0
- package/dist/look/judge.js +151 -0
- package/dist/look/judge.js.map +1 -0
- package/dist/look/lint-static.d.ts +45 -0
- package/dist/look/lint-static.d.ts.map +1 -0
- package/dist/look/lint-static.js +241 -0
- package/dist/look/lint-static.js.map +1 -0
- package/dist/look/rubric.d.ts +70 -0
- package/dist/look/rubric.d.ts.map +1 -0
- package/dist/look/rubric.js +169 -0
- package/dist/look/rubric.js.map +1 -0
- package/dist/meshy/import.d.ts +7 -1
- package/dist/meshy/import.d.ts.map +1 -1
- package/dist/meshy/import.js +80 -6
- package/dist/meshy/import.js.map +1 -1
- package/dist/migrate-three/CompatibilityWarnings.d.ts +6 -0
- package/dist/migrate-three/CompatibilityWarnings.d.ts.map +1 -0
- package/dist/migrate-three/CompatibilityWarnings.js +24 -0
- package/dist/migrate-three/CompatibilityWarnings.js.map +1 -0
- package/dist/migrate-three/ImportMap.d.ts +19 -0
- package/dist/migrate-three/ImportMap.d.ts.map +1 -0
- package/dist/migrate-three/ImportMap.js +35 -0
- package/dist/migrate-three/ImportMap.js.map +1 -0
- package/dist/migrate-three/R3fMigration.d.ts +32 -0
- package/dist/migrate-three/R3fMigration.d.ts.map +1 -0
- package/dist/migrate-three/R3fMigration.js +70 -0
- package/dist/migrate-three/R3fMigration.js.map +1 -0
- package/dist/migrate-three/ThreeToA3DAdapter.d.ts +8 -0
- package/dist/migrate-three/ThreeToA3DAdapter.d.ts.map +1 -0
- package/dist/migrate-three/ThreeToA3DAdapter.js +20 -0
- package/dist/migrate-three/ThreeToA3DAdapter.js.map +1 -0
- package/dist/migrate-three/emit.d.ts +21 -0
- package/dist/migrate-three/emit.d.ts.map +1 -0
- package/dist/migrate-three/emit.js +117 -0
- package/dist/migrate-three/emit.js.map +1 -0
- package/dist/migrate-three/mappings.d.ts +21 -0
- package/dist/migrate-three/mappings.d.ts.map +1 -0
- package/dist/migrate-three/mappings.js +42 -0
- package/dist/migrate-three/mappings.js.map +1 -0
- package/dist/migrate-three/parse.d.ts +20 -0
- package/dist/migrate-three/parse.d.ts.map +1 -0
- package/dist/migrate-three/parse.js +56 -0
- package/dist/migrate-three/parse.js.map +1 -0
- package/dist/migrate-three/report.d.ts +18 -0
- package/dist/migrate-three/report.d.ts.map +1 -0
- package/dist/migrate-three/report.js +16 -0
- package/dist/migrate-three/report.js.map +1 -0
- package/dist/pull-bridge/adapters.d.ts +1 -1
- package/dist/pull-bridge/adapters.d.ts.map +1 -1
- package/dist/pull-bridge/adapters.js +17 -4
- package/dist/pull-bridge/adapters.js.map +1 -1
- package/dist/pull-bridge/provenance.d.ts.map +1 -1
- package/dist/pull-bridge/provenance.js +3 -2
- package/dist/pull-bridge/provenance.js.map +1 -1
- package/dist/pull-bridge/pullable.d.ts.map +1 -1
- package/dist/pull-bridge/pullable.js +14 -3
- package/dist/pull-bridge/pullable.js.map +1 -1
- package/dist/pull-bridge/scoring.d.ts +36 -8
- package/dist/pull-bridge/scoring.d.ts.map +1 -1
- package/dist/pull-bridge/scoring.js +143 -47
- package/dist/pull-bridge/scoring.js.map +1 -1
- package/dist/pull-bridge/search.d.ts +2 -0
- package/dist/pull-bridge/search.d.ts.map +1 -1
- package/dist/pull-bridge/search.js +17 -10
- package/dist/pull-bridge/search.js.map +1 -1
- package/dist/pull-bridge.d.ts +2 -2
- package/dist/pull-bridge.d.ts.map +1 -1
- package/dist/pull-bridge.js +24 -8
- package/dist/pull-bridge.js.map +1 -1
- package/package.json +6 -3
- package/skills/agent-files/AGENTS.md +3 -0
- package/skills/aura3d-animation-studio/SKILL.md +153 -0
- package/skills/aura3d-animation-studio/references/shot-looks.md +26 -0
- package/skills/aura3d-art-direction/SKILL.md +84 -0
- package/skills/aura3d-art-direction/references/failure-gallery.md +64 -0
- package/skills/aura3d-art-direction/references/framing-and-shots.md +45 -0
- package/skills/aura3d-art-direction/references/look-recipes.md +32 -0
- package/skills/aura3d-art-direction/references/quality-bar.md +103 -0
- package/skills/aura3d-art-direction/references/reference-frames.md +82 -0
- package/skills/aura3d-assets/SKILL.md +132 -0
- package/skills/aura3d-assets/references/preview-under-look.md +26 -0
- package/skills/aura3d-browser-game/SKILL.md +127 -0
- package/skills/aura3d-browser-game/references/genre-looks.md +52 -0
- package/skills/aura3d-character-animation/SKILL.md +129 -0
- package/skills/aura3d-character-animation/references/stage-and-lighting.md +31 -0
- package/skills/aura3d-core/SKILL.md +121 -0
- package/skills/aura3d-core/references/boundaries.md +91 -0
- package/skills/aura3d-evidence-review/SKILL.md +106 -0
- package/skills/aura3d-game-art/SKILL.md +118 -0
- package/skills/aura3d-game-art/references/sheet-check.mjs +58 -0
- package/skills/aura3d-game-art/references/sprite-palettes.md +25 -0
- package/skills/aura3d-materials-environments/SKILL.md +139 -0
- package/skills/aura3d-performance/SKILL.md +97 -0
- package/skills/aura3d-retexture/SKILL.md +115 -0
- package/skills/aura3d-retexture/references/geometry-hash.mjs +89 -0
- package/skills/aura3d-scene-authoring/SKILL.md +132 -0
- package/skills/aura3d-scene-authoring/references/look-by-family.md +28 -0
- package/skills/aura3d-threejs-migration/SKILL.md +125 -0
- package/skills/aura3d-threejs-migration/references/look-mapping.md +27 -0
- package/skills/llms.txt +117 -0
- package/skills/manifest.json +163 -0
- package/skills/meshy-cli/SKILL.md +133 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
const COMPONENT_BYTES = { 5120: 1, 5121: 1, 5122: 2, 5123: 2, 5125: 4, 5126: 4 };
|
|
2
|
+
const TYPE_COUNT = { SCALAR: 1, VEC2: 2, VEC3: 3, VEC4: 4, MAT4: 16 };
|
|
3
|
+
function accessorView(json, index) {
|
|
4
|
+
const accessor = json.accessors?.[index];
|
|
5
|
+
if (!accessor || accessor.count === undefined || accessor.type === undefined || accessor.componentType === undefined)
|
|
6
|
+
return undefined;
|
|
7
|
+
const view = json.bufferViews?.[accessor.bufferView ?? -1];
|
|
8
|
+
// EXT_meshopt_compression bufferViews address a virtual decoded buffer —
|
|
9
|
+
// byteOffset is not an offset into the file's BIN chunk. Treat those
|
|
10
|
+
// accessors as unmeasurable (skipped) rather than indexing out of range.
|
|
11
|
+
if (view?.extensions?.EXT_meshopt_compression !== undefined)
|
|
12
|
+
return undefined;
|
|
13
|
+
const componentBytes = COMPONENT_BYTES[accessor.componentType];
|
|
14
|
+
const count = TYPE_COUNT[accessor.type];
|
|
15
|
+
if (componentBytes === undefined || count === undefined)
|
|
16
|
+
return undefined;
|
|
17
|
+
const stride = view?.byteStride ?? componentBytes * count;
|
|
18
|
+
return { componentType: accessor.componentType, count: accessor.count, type: accessor.type, offset: (view?.byteOffset ?? 0) + (accessor.byteOffset ?? 0), stride };
|
|
19
|
+
}
|
|
20
|
+
function readIndex(bin, view, i) {
|
|
21
|
+
const at = view.offset + i * view.stride;
|
|
22
|
+
return view.componentType === 5123 ? bin.readUInt16LE(at) : view.componentType === 5125 ? bin.readUInt32LE(at) : bin.readUInt8(at);
|
|
23
|
+
}
|
|
24
|
+
function readVec2(bin, view, i) {
|
|
25
|
+
const at = view.offset + i * view.stride;
|
|
26
|
+
return [bin.readFloatLE(at), bin.readFloatLE(at + 4)];
|
|
27
|
+
}
|
|
28
|
+
function readVec3(bin, view, i) {
|
|
29
|
+
const at = view.offset + i * view.stride;
|
|
30
|
+
return [bin.readFloatLE(at), bin.readFloatLE(at + 4), bin.readFloatLE(at + 8)];
|
|
31
|
+
}
|
|
32
|
+
/** Image header sniff: PNG IHDR (BE u32 @16,20), JPEG SOF (BE u16 height/width), KTX2 (LE u32 @20,24). */
|
|
33
|
+
export function sniffImageSize(bytes, mime) {
|
|
34
|
+
if (bytes.length >= 24 && bytes.readUInt32BE(0) === 0x89504e47) {
|
|
35
|
+
return [bytes.readUInt32BE(16), bytes.readUInt32BE(20)];
|
|
36
|
+
}
|
|
37
|
+
if (bytes.length >= 4 && bytes[0] === 0xff && bytes[1] === 0xd8) {
|
|
38
|
+
for (let at = 2; at + 9 < bytes.length;) {
|
|
39
|
+
if (bytes[at] !== 0xff) {
|
|
40
|
+
at += 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const marker = bytes[at + 1];
|
|
44
|
+
if (marker >= 0xc0 && marker <= 0xcf && marker !== 0xc4 && marker !== 0xc8 && marker !== 0xcc) {
|
|
45
|
+
return [bytes.readUInt16BE(at + 7), bytes.readUInt16BE(at + 5)];
|
|
46
|
+
}
|
|
47
|
+
at += 2 + (bytes.readUInt16BE(at + 2) || 2);
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
// KTX2: \xABKTX 20\xBB\r\n\x1A\n magic, then LE u32 fields; pixelWidth @20, pixelHeight @24.
|
|
52
|
+
if (bytes.length >= 28 && bytes.readUInt32LE(0) === 0xbb3254ab) {
|
|
53
|
+
return [bytes.readUInt32LE(20), bytes.readUInt32LE(24)];
|
|
54
|
+
}
|
|
55
|
+
// KTX1 magic 0xAB 4B 54 58 20 31 31 BB: pixelWidth @36, pixelHeight @40.
|
|
56
|
+
if (bytes.length >= 44 && bytes.readUInt32LE(0) === 0xbb313554) {
|
|
57
|
+
return [bytes.readUInt32LE(36), bytes.readUInt32LE(40)];
|
|
58
|
+
}
|
|
59
|
+
void mime;
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
/** Resolves the base-colour texture's pixel size for a material index. */
|
|
63
|
+
function materialTextureSize(json, bin, materialIndex) {
|
|
64
|
+
if (materialIndex === undefined)
|
|
65
|
+
return undefined;
|
|
66
|
+
const material = json.materials?.[materialIndex];
|
|
67
|
+
const info = material?.pbrMetallicRoughness?.baseColorTexture;
|
|
68
|
+
const textureIndex = info?.extensions?.KHR_texture_basisu?.index ?? info?.index;
|
|
69
|
+
if (textureIndex === undefined)
|
|
70
|
+
return undefined;
|
|
71
|
+
const sourceIndex = json.textures?.[textureIndex]?.extensions?.KHR_texture_basisu?.source ?? json.textures?.[textureIndex]?.source;
|
|
72
|
+
if (sourceIndex === undefined)
|
|
73
|
+
return undefined;
|
|
74
|
+
const image = json.images?.[sourceIndex];
|
|
75
|
+
if (image?.bufferView === undefined)
|
|
76
|
+
return undefined;
|
|
77
|
+
const view = json.bufferViews?.[image.bufferView];
|
|
78
|
+
if (!view)
|
|
79
|
+
return undefined;
|
|
80
|
+
const bytes = bin.subarray(view.byteOffset ?? 0, (view.byteOffset ?? 0) + view.byteLength);
|
|
81
|
+
return sniffImageSize(bytes, image.mimeType);
|
|
82
|
+
}
|
|
83
|
+
function metersPerPixel(camera) {
|
|
84
|
+
const fovRadians = (camera.fovDegrees * Math.PI) / 180;
|
|
85
|
+
return (2 * camera.distance * Math.tan(fovRadians / 2)) / camera.viewportHeight;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Measures the texel-density report for a GLB against `camera`. Returns a
|
|
89
|
+
* report with `trianglesMeasured: 0` when no primitive can be measured —
|
|
90
|
+
* the gate treats that as "no evidence" rather than a pass.
|
|
91
|
+
*/
|
|
92
|
+
export function measureTexelDensity(json, bin, camera) {
|
|
93
|
+
const full = json;
|
|
94
|
+
const skipped = { triangles: 0 };
|
|
95
|
+
if (!bin) {
|
|
96
|
+
return { trianglesMeasured: 0, trianglesSkipped: 0, camera };
|
|
97
|
+
}
|
|
98
|
+
/** Area-weighted samples per material texture size. */
|
|
99
|
+
const samples = [];
|
|
100
|
+
for (const mesh of full.meshes ?? []) {
|
|
101
|
+
for (const primitive of mesh.primitives ?? []) {
|
|
102
|
+
const mode = primitive.mode ?? 4;
|
|
103
|
+
const attrs = primitive.attributes ?? {};
|
|
104
|
+
if (mode !== 4 || attrs.POSITION === undefined || attrs.TEXCOORD_0 === undefined) {
|
|
105
|
+
const primTriangles = mode !== 4 ? 0 : Math.floor((full.accessors?.[attrs.POSITION]?.count ?? 0) / 3);
|
|
106
|
+
skipped.triangles += primTriangles;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
const positions = accessorView(full, attrs.POSITION);
|
|
110
|
+
const uvs = accessorView(full, attrs.TEXCOORD_0);
|
|
111
|
+
const textureSize = materialTextureSize(full, bin, primitive.material);
|
|
112
|
+
const indexView = typeof primitive.indices === "number" ? accessorView(full, primitive.indices) : undefined;
|
|
113
|
+
// An indexed primitive whose index accessor is unreadable (e.g. an
|
|
114
|
+
// EXT_meshopt_compression bufferView) must be skipped, not read as
|
|
115
|
+
// non-indexed — that would pair the wrong vertices into triangles.
|
|
116
|
+
const indicesUnreadable = typeof primitive.indices === "number" && !indexView;
|
|
117
|
+
if (!positions || !uvs || indicesUnreadable || !textureSize || textureSize[0] <= 0 || textureSize[1] <= 0) {
|
|
118
|
+
const indexCountRaw = typeof primitive.indices === "number" ? full.accessors?.[primitive.indices]?.count : undefined;
|
|
119
|
+
const vertexCountRaw = full.accessors?.[attrs.POSITION]?.count;
|
|
120
|
+
skipped.triangles += Math.floor((indexCountRaw ?? vertexCountRaw ?? 0) / 3);
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
const indexCount = indexView?.count ?? positions.count;
|
|
124
|
+
for (let i = 0; i + 2 < indexCount; i += 3) {
|
|
125
|
+
const [a, b, c] = indexView
|
|
126
|
+
? [readIndex(bin, indexView, i), readIndex(bin, indexView, i + 1), readIndex(bin, indexView, i + 2)]
|
|
127
|
+
: [i, i + 1, i + 2];
|
|
128
|
+
if (a >= positions.count || b >= positions.count || c >= positions.count)
|
|
129
|
+
continue;
|
|
130
|
+
const [p0, p1, p2] = [readVec3(bin, positions, a), readVec3(bin, positions, b), readVec3(bin, positions, c)];
|
|
131
|
+
const [t0, t1, t2] = [readVec2(bin, uvs, a), readVec2(bin, uvs, b), readVec2(bin, uvs, c)];
|
|
132
|
+
const e1 = [p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2]];
|
|
133
|
+
const e2 = [p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2]];
|
|
134
|
+
const cross = [
|
|
135
|
+
e1[1] * e2[2] - e1[2] * e2[1],
|
|
136
|
+
e1[2] * e2[0] - e1[0] * e2[2],
|
|
137
|
+
e1[0] * e2[1] - e1[1] * e2[0]
|
|
138
|
+
];
|
|
139
|
+
const worldArea = 0.5 * Math.hypot(cross[0], cross[1], cross[2]);
|
|
140
|
+
const uvArea = 0.5 * Math.abs((t1[0] - t0[0]) * (t2[1] - t0[1]) - (t2[0] - t0[0]) * (t1[1] - t0[1]));
|
|
141
|
+
if (worldArea <= 0 || uvArea <= 0)
|
|
142
|
+
continue;
|
|
143
|
+
// Texels spanned by the triangle's UV footprint (area-units → texels).
|
|
144
|
+
const uvTexels = Math.sqrt(uvArea * textureSize[0] * textureSize[1]);
|
|
145
|
+
samples.push({ texelsPerMeter: uvTexels / Math.sqrt(worldArea), worldArea, textureSize });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const measured = samples.length;
|
|
150
|
+
if (measured === 0)
|
|
151
|
+
return { trianglesMeasured: 0, trianglesSkipped: skipped.triangles, camera };
|
|
152
|
+
const sorted = [...samples].sort((x, y) => x.texelsPerMeter - y.texelsPerMeter);
|
|
153
|
+
const totalArea = samples.reduce((sum, s) => sum + s.worldArea, 0);
|
|
154
|
+
const quantile = (q) => {
|
|
155
|
+
let acc = 0;
|
|
156
|
+
for (const s of sorted) {
|
|
157
|
+
acc += s.worldArea;
|
|
158
|
+
if (acc >= q * totalArea)
|
|
159
|
+
return s.texelsPerMeter;
|
|
160
|
+
}
|
|
161
|
+
return sorted[sorted.length - 1].texelsPerMeter;
|
|
162
|
+
};
|
|
163
|
+
const median = quantile(0.5);
|
|
164
|
+
const mpp = metersPerPixel(camera);
|
|
165
|
+
const medianSize = sorted[Math.floor((sorted.length - 1) / 2)].textureSize;
|
|
166
|
+
return {
|
|
167
|
+
trianglesMeasured: measured,
|
|
168
|
+
trianglesSkipped: skipped.triangles,
|
|
169
|
+
p10: quantile(0.1) * mpp,
|
|
170
|
+
p50: median * mpp,
|
|
171
|
+
p90: quantile(0.9) * mpp,
|
|
172
|
+
texelsPerMeterP50: median,
|
|
173
|
+
camera,
|
|
174
|
+
textureSize: medianSize
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=texel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"texel.js","sourceRoot":"","sources":["../../../../../packages/aura3d-cli/src/admission/texel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { AdmissionGltfJson } from "./glb.js";
|
|
2
|
+
export interface TextureChannelStats {
|
|
3
|
+
readonly mean: number;
|
|
4
|
+
readonly stdDev: number;
|
|
5
|
+
/** Fraction of texels whose channel value sits in `inRange` (0–255). */
|
|
6
|
+
readonly inRange?: number;
|
|
7
|
+
}
|
|
8
|
+
export interface TextureSlotStats {
|
|
9
|
+
readonly materialIndex: number;
|
|
10
|
+
readonly materialName?: string;
|
|
11
|
+
readonly slot: "baseColor" | "normal" | "metallicRoughness" | "occlusion" | "emissive";
|
|
12
|
+
readonly width: number;
|
|
13
|
+
readonly height: number;
|
|
14
|
+
readonly mimeType?: string;
|
|
15
|
+
readonly powerOfTwo: boolean;
|
|
16
|
+
/** Decoded-channel stats (undefined when the image cannot be decoded). */
|
|
17
|
+
readonly channels?: readonly TextureChannelStats[];
|
|
18
|
+
/** Normal-map vector-length stats. */
|
|
19
|
+
readonly normalLength?: {
|
|
20
|
+
readonly mean: number;
|
|
21
|
+
readonly inUnitRange: number;
|
|
22
|
+
readonly meanBlue: number;
|
|
23
|
+
};
|
|
24
|
+
/** sRGB luminance histogram (base colour). */
|
|
25
|
+
readonly luminance?: {
|
|
26
|
+
readonly mean: number;
|
|
27
|
+
readonly inRange30to240: number;
|
|
28
|
+
};
|
|
29
|
+
/** ORM channels whose σ < 0.004 (constant → "replace with factor"). */
|
|
30
|
+
readonly constantChannels?: readonly string[];
|
|
31
|
+
readonly error?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface TextureSanityReport {
|
|
34
|
+
readonly available: boolean;
|
|
35
|
+
/** Reason the decode could not run (sharp missing, no images, …). */
|
|
36
|
+
readonly unavailableReason?: string;
|
|
37
|
+
readonly textures: readonly TextureSlotStats[];
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Measures G6 stats for every material texture slot in the glTF.
|
|
41
|
+
* `gltfDir` resolves external image URIs (gltf container); GLB images come
|
|
42
|
+
* from `bin`.
|
|
43
|
+
*/
|
|
44
|
+
export declare function measureTextureSanity(json: AdmissionGltfJson, bin: Buffer | undefined, gltfDir: string, repoRoot: string): Promise<TextureSanityReport>;
|
|
45
|
+
//# sourceMappingURL=textureStats.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textureStats.d.ts","sourceRoot":"","sources":["../../../../../packages/aura3d-cli/src/admission/textureStats.ts"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAGlD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,wEAAwE;IACxE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,WAAW,GAAG,QAAQ,GAAG,mBAAmB,GAAG,WAAW,GAAG,UAAU,CAAC;IACvF,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,0EAA0E;IAC1E,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACnD,sCAAsC;IACtC,QAAQ,CAAC,YAAY,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3G,8CAA8C;IAC9C,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;IAChF,uEAAuE;IACvE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IACpC,QAAQ,CAAC,QAAQ,EAAE,SAAS,gBAAgB,EAAE,CAAC;CAChD;AAmHD;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAyF5J"}
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRD-05 §6.4 G6 — texture sanity measurement on 256² decoded proxies.
|
|
3
|
+
*
|
|
4
|
+
* Pixel decode needs `sharp`, which is a `tools/asset-optimize` dependency
|
|
5
|
+
* (the CLI itself carries no image deps per §4.4). Resolution follows the
|
|
6
|
+
* established lane-05 bridge: `createRequire(<repo>/tools/asset-optimize/
|
|
7
|
+
* package.json)` + `import(resolve("sharp"))`. When the tool deps are not
|
|
8
|
+
* installed (plain `pnpm install` without `tools/asset-optimize` npm
|
|
9
|
+
* install), the report is `available: false` and G6 records a fail —
|
|
10
|
+
* release admission requires the measurement, never assumes it.
|
|
11
|
+
*
|
|
12
|
+
* Measured per §6.4 G6:
|
|
13
|
+
* - normal maps: decoded vector length within [0.9, 1.1] for ≥ 95 % texels,
|
|
14
|
+
* mean B ≥ 0.7;
|
|
15
|
+
* - ORM/metallicRoughness: R/G/B not all constant; a channel with σ < 0.004
|
|
16
|
+
* is flagged "replace texture with factor";
|
|
17
|
+
* - base colour: sRGB luminance (0.2126R+0.7152G+0.0722B on 0–255) within
|
|
18
|
+
* [30, 240] on ≥ 95 % texels; metals (metallic ≥ 0.9 factor or ORM
|
|
19
|
+
* median ≥ 0.9) require ≥ 140;
|
|
20
|
+
* - no texture above `profile.maxTextureDimension`; no non-power-of-two
|
|
21
|
+
* dimensions (post-optimize rule; recorded as `npot` flags).
|
|
22
|
+
*/
|
|
23
|
+
import { createRequire } from "node:module";
|
|
24
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
25
|
+
import { dirname, extname, resolve } from "node:path";
|
|
26
|
+
import { sniffImageSize } from "./texel.js";
|
|
27
|
+
function isPowerOfTwo(n) {
|
|
28
|
+
return n > 0 && (n & (n - 1)) === 0;
|
|
29
|
+
}
|
|
30
|
+
async function loadSharp(repoRoot) {
|
|
31
|
+
try {
|
|
32
|
+
const toolRequire = createRequire(resolve(repoRoot, "tools", "asset-optimize", "package.json"));
|
|
33
|
+
const mod = (await import(toolRequire.resolve("sharp")));
|
|
34
|
+
return (mod.default ?? mod);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return undefined;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
const PROXY = 256;
|
|
41
|
+
/** Extracts image bytes for a material slot's texture reference. */
|
|
42
|
+
function imageBytesFor(json, bin, gltfDir, texInfo) {
|
|
43
|
+
const textureIndex = texInfo?.extensions?.KHR_texture_basisu?.index ?? texInfo?.index;
|
|
44
|
+
if (textureIndex === undefined)
|
|
45
|
+
return undefined;
|
|
46
|
+
const texture = json.textures?.[textureIndex];
|
|
47
|
+
const sourceIndex = texture?.extensions?.KHR_texture_basisu?.source ?? texture?.source;
|
|
48
|
+
const image = sourceIndex !== undefined ? json.images?.[sourceIndex] : undefined;
|
|
49
|
+
if (!image)
|
|
50
|
+
return undefined;
|
|
51
|
+
if (image.bufferView !== undefined && bin) {
|
|
52
|
+
const view = json.bufferViews?.[image.bufferView];
|
|
53
|
+
if (!view)
|
|
54
|
+
return undefined;
|
|
55
|
+
return { bytes: bin.subarray(view.byteOffset ?? 0, (view.byteOffset ?? 0) + view.byteLength), mimeType: image.mimeType };
|
|
56
|
+
}
|
|
57
|
+
if (image.uri && !image.uri.startsWith("data:")) {
|
|
58
|
+
const file = resolve(gltfDir, decodeURIComponent(image.uri));
|
|
59
|
+
if (!existsSync(file))
|
|
60
|
+
return undefined;
|
|
61
|
+
return { bytes: readFileSync(file), mimeType: image.mimeType ?? `image/${extname(file).slice(1)}` };
|
|
62
|
+
}
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
function channelStats(data, width, height, channels) {
|
|
66
|
+
const px = width * height;
|
|
67
|
+
const sums = [0, 0, 0, 0];
|
|
68
|
+
const sumsSq = [0, 0, 0, 0];
|
|
69
|
+
let normalInRange = 0;
|
|
70
|
+
let normalBlueSum = 0;
|
|
71
|
+
let luminanceInRange = 0;
|
|
72
|
+
let luminanceSum = 0;
|
|
73
|
+
for (let i = 0; i < px; i++) {
|
|
74
|
+
const at = i * channels;
|
|
75
|
+
const r = data[at] ?? 0;
|
|
76
|
+
const g = data[at + 1] ?? 0;
|
|
77
|
+
const b = data[at + 2] ?? 0;
|
|
78
|
+
sums[0] += r;
|
|
79
|
+
sums[1] += g;
|
|
80
|
+
sums[2] += b;
|
|
81
|
+
sumsSq[0] += r * r;
|
|
82
|
+
sumsSq[1] += g * g;
|
|
83
|
+
sumsSq[2] += b * b;
|
|
84
|
+
const nx = r / 127.5 - 1;
|
|
85
|
+
const ny = g / 127.5 - 1;
|
|
86
|
+
const nz = b / 127.5 - 1;
|
|
87
|
+
const len = Math.hypot(nx, ny, nz);
|
|
88
|
+
if (len >= 0.9 && len <= 1.1)
|
|
89
|
+
normalInRange += 1;
|
|
90
|
+
normalBlueSum += nz;
|
|
91
|
+
const lum = 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
92
|
+
luminanceSum += lum;
|
|
93
|
+
if (lum >= 30 && lum <= 240)
|
|
94
|
+
luminanceInRange += 1;
|
|
95
|
+
}
|
|
96
|
+
const channels_ = [];
|
|
97
|
+
const constantChannels = [];
|
|
98
|
+
const names = ["R", "G", "B", "A"];
|
|
99
|
+
for (let c = 0; c < Math.min(channels, 4); c++) {
|
|
100
|
+
const mean = (sums[c] ?? 0) / px;
|
|
101
|
+
const stdDev = Math.sqrt(Math.max(0, (sumsSq[c] ?? 0) / px - mean * mean));
|
|
102
|
+
channels_.push({ mean, stdDev });
|
|
103
|
+
if (stdDev / 255 < 0.004)
|
|
104
|
+
constantChannels.push(names[c]);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
channels: channels_,
|
|
108
|
+
normalLength: { mean: 0, inUnitRange: normalInRange / px, meanBlue: normalBlueSum / px },
|
|
109
|
+
luminance: { mean: luminanceSum / px, inRange30to240: luminanceInRange / px },
|
|
110
|
+
constantChannels
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Measures G6 stats for every material texture slot in the glTF.
|
|
115
|
+
* `gltfDir` resolves external image URIs (gltf container); GLB images come
|
|
116
|
+
* from `bin`.
|
|
117
|
+
*/
|
|
118
|
+
export async function measureTextureSanity(json, bin, gltfDir, repoRoot) {
|
|
119
|
+
const full = json;
|
|
120
|
+
const sharp = await loadSharp(repoRoot);
|
|
121
|
+
const jobs = [];
|
|
122
|
+
const materials = (full.materials ?? []);
|
|
123
|
+
materials.forEach((material, materialIndex) => {
|
|
124
|
+
const slots = [
|
|
125
|
+
["baseColor", material.pbrMetallicRoughness?.baseColorTexture],
|
|
126
|
+
["normal", material.normalTexture],
|
|
127
|
+
["metallicRoughness", material.pbrMetallicRoughness?.metallicRoughnessTexture],
|
|
128
|
+
["occlusion", material.occlusionTexture],
|
|
129
|
+
["emissive", material.emissiveTexture]
|
|
130
|
+
];
|
|
131
|
+
for (const [slot, info] of slots) {
|
|
132
|
+
const image = imageBytesFor(full, bin, gltfDir, info);
|
|
133
|
+
if (image)
|
|
134
|
+
jobs.push({ slot, materialIndex, materialName: material.name, bytes: image.bytes, mimeType: image.mimeType });
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
if (jobs.length === 0) {
|
|
138
|
+
return { available: true, textures: [] };
|
|
139
|
+
}
|
|
140
|
+
if (!sharp) {
|
|
141
|
+
return {
|
|
142
|
+
available: false,
|
|
143
|
+
unavailableReason: "sharp is not installed — run `npm install` in tools/asset-optimize (G6 decode needs it).",
|
|
144
|
+
textures: jobs.map((job) => {
|
|
145
|
+
const size = sniffImageSize(job.bytes, job.mimeType);
|
|
146
|
+
return {
|
|
147
|
+
slot: job.slot,
|
|
148
|
+
materialIndex: job.materialIndex,
|
|
149
|
+
...(job.materialName ? { materialName: job.materialName } : {}),
|
|
150
|
+
width: size?.[0] ?? 0,
|
|
151
|
+
height: size?.[1] ?? 0,
|
|
152
|
+
...(job.mimeType ? { mimeType: job.mimeType } : {}),
|
|
153
|
+
powerOfTwo: size ? isPowerOfTwo(size[0]) && isPowerOfTwo(size[1]) : false,
|
|
154
|
+
error: "decode-unavailable"
|
|
155
|
+
};
|
|
156
|
+
})
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
const textures = [];
|
|
160
|
+
for (const job of jobs) {
|
|
161
|
+
const size = sniffImageSize(job.bytes, job.mimeType);
|
|
162
|
+
const base = {
|
|
163
|
+
slot: job.slot,
|
|
164
|
+
materialIndex: job.materialIndex,
|
|
165
|
+
...(job.materialName ? { materialName: job.materialName } : {}),
|
|
166
|
+
width: size?.[0] ?? 0,
|
|
167
|
+
height: size?.[1] ?? 0,
|
|
168
|
+
...(job.mimeType ? { mimeType: job.mimeType } : {}),
|
|
169
|
+
powerOfTwo: size ? isPowerOfTwo(size[0]) && isPowerOfTwo(size[1]) : false
|
|
170
|
+
};
|
|
171
|
+
try {
|
|
172
|
+
let pipeline = sharp(job.bytes);
|
|
173
|
+
const meta = await pipeline.metadata();
|
|
174
|
+
const srcW = size?.[0] ?? meta.width ?? 0;
|
|
175
|
+
const srcH = size?.[1] ?? meta.height ?? 0;
|
|
176
|
+
if (srcW > PROXY || srcH > PROXY) {
|
|
177
|
+
const scale = Math.min(1, PROXY / Math.max(srcW, srcH));
|
|
178
|
+
pipeline = pipeline.resize(Math.max(1, Math.round(srcW * scale)), Math.max(1, Math.round(srcH * scale)), { fit: "fill" });
|
|
179
|
+
}
|
|
180
|
+
const raw = await pipeline.raw().toBuffer({ resolveWithObject: true });
|
|
181
|
+
const stats = channelStats(raw.data, raw.info.width, raw.info.height, raw.info.channels);
|
|
182
|
+
const space = meta.space;
|
|
183
|
+
textures.push({
|
|
184
|
+
...base,
|
|
185
|
+
width: raw.info.width || base.width,
|
|
186
|
+
height: raw.info.height || base.height,
|
|
187
|
+
channels: stats.channels,
|
|
188
|
+
...(job.slot === "normal" ? { normalLength: { ...stats.normalLength, meanBlue: stats.normalLength.meanBlue } } : {}),
|
|
189
|
+
...(job.slot === "baseColor" ? { luminance: stats.luminance } : {}),
|
|
190
|
+
...(job.slot === "metallicRoughness" || job.slot === "occlusion" ? { constantChannels: stats.constantChannels } : {}),
|
|
191
|
+
...(space && space !== "srgb" && job.slot === "baseColor" ? { error: `colorspace-${space}` } : {})
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
catch (error) {
|
|
195
|
+
// KTX2/basisu sources can't be decoded by sharp — sniffed dims still land.
|
|
196
|
+
textures.push({ ...base, error: `undecodable: ${error instanceof Error ? error.message.slice(0, 80) : String(error)}` });
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return { available: true, textures };
|
|
200
|
+
}
|
|
201
|
+
//# sourceMappingURL=textureStats.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"textureStats.js","sourceRoot":"","sources":["../../../../../packages/aura3d-cli/src/admission/textureStats.ts"],"names":[],"mappings":"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"}
|
|
@@ -7,13 +7,57 @@ export interface AnimationAssetValidationOptions {
|
|
|
7
7
|
readonly requiredActions?: readonly string[];
|
|
8
8
|
/** Require the asset to declare at least one clip at all (proxy for "rigged/animated"). */
|
|
9
9
|
readonly requireRig?: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* T4.6 (PRD-06) — geometry + clip-duration inspection for hero profiles,
|
|
12
|
+
* filled by the lane's GLB reader (`commands/prd06/validateHero.ts`). Hero
|
|
13
|
+
* profile checks run only when this is present.
|
|
14
|
+
*/
|
|
15
|
+
readonly inspection?: AnimationAssetInspection;
|
|
16
|
+
/**
|
|
17
|
+
* T4.6 — a named hero profile (`hero-character` floor; `template-hero` §6.9
|
|
18
|
+
* bar). Profiles add geometry/texture/duration checks and emit reason codes;
|
|
19
|
+
* they never suppress the clip-map messages above.
|
|
20
|
+
*/
|
|
21
|
+
readonly profile?: AnimationAssetHeroProfile;
|
|
10
22
|
}
|
|
23
|
+
/** T4.6 — geometry/texture/duration facts the hero profiles evaluate. */
|
|
24
|
+
export interface AnimationAssetInspection {
|
|
25
|
+
readonly triangleCount: number;
|
|
26
|
+
readonly skinCount: number;
|
|
27
|
+
/** Max joints across skins (glTF `skins[].joints.length`). */
|
|
28
|
+
readonly jointCount: number;
|
|
29
|
+
readonly clips: readonly {
|
|
30
|
+
readonly name: string;
|
|
31
|
+
readonly duration: number;
|
|
32
|
+
}[];
|
|
33
|
+
readonly hasBaseColorTexture: boolean;
|
|
34
|
+
}
|
|
35
|
+
export type AnimationAssetHeroProfile = "hero-character" | "template-hero";
|
|
36
|
+
export declare const HERO_NOT_A_CHARACTER = "HERO_NOT_A_CHARACTER";
|
|
37
|
+
export declare const HERO_NO_SKIN = "HERO_NO_SKIN";
|
|
38
|
+
export declare const HERO_TOO_FEW_JOINTS = "HERO_TOO_FEW_JOINTS";
|
|
39
|
+
export declare const HERO_MISSING_CLIP = "HERO_MISSING_CLIP";
|
|
40
|
+
export declare const HERO_CLIP_TOO_SHORT = "HERO_CLIP_TOO_SHORT";
|
|
41
|
+
export declare const HERO_UNTEXTURED = "HERO_UNTEXTURED";
|
|
42
|
+
/** §6.9 clip set for `template-hero`; `hero-character` needs the locomotion subset. */
|
|
43
|
+
export declare const HERO_CHARACTER_ACTIONS: readonly ["idle", "walk", "run", "jump-start", "jump-loop", "land"];
|
|
44
|
+
export declare const TEMPLATE_HERO_ACTIONS: readonly ["idle", "walk", "run", "jump-start", "jump-loop", "land", "sprint", "turn-l", "turn-r", "interact", "hit-react", "attack"];
|
|
45
|
+
export interface AnimationAssetHeroProfileDefinition {
|
|
46
|
+
readonly profile: AnimationAssetHeroProfile;
|
|
47
|
+
readonly minTriangles: number;
|
|
48
|
+
readonly minJoints: number;
|
|
49
|
+
readonly requiredActions: readonly string[];
|
|
50
|
+
readonly minClipDuration: number;
|
|
51
|
+
}
|
|
52
|
+
export declare const ANIMATION_ASSET_HERO_PROFILES: Record<AnimationAssetHeroProfile, AnimationAssetHeroProfileDefinition>;
|
|
11
53
|
export interface AnimationAssetValidationReport {
|
|
12
54
|
readonly ok: boolean;
|
|
13
55
|
readonly messages: readonly string[];
|
|
14
56
|
readonly failures: readonly string[];
|
|
15
57
|
readonly missingActions: readonly string[];
|
|
16
58
|
readonly missingClips: readonly string[];
|
|
59
|
+
/** T4.6 — reason codes for the hero profiles (`[]` on the legacy path). */
|
|
60
|
+
readonly reasonCodes: readonly string[];
|
|
17
61
|
}
|
|
18
62
|
export declare const DEFAULT_ANIMATION_ACTIONS: readonly ["idle", "walk", "run"];
|
|
19
63
|
export declare function validateAnimationAssets(options: AnimationAssetValidationOptions): AnimationAssetValidationReport;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"animation-asset-validator.d.ts","sourceRoot":"","sources":["../../../../packages/aura3d-cli/src/animation-asset-validator.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,+BAA+B;IAC9C,iFAAiF;IACjF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,0DAA0D;IAC1D,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"animation-asset-validator.d.ts","sourceRoot":"","sources":["../../../../packages/aura3d-cli/src/animation-asset-validator.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,+BAA+B;IAC9C,iFAAiF;IACjF,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,0DAA0D;IAC1D,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC7C,2FAA2F;IAC3F,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,wBAAwB,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,yBAAyB,CAAC;CAC9C;AAED,yEAAyE;AACzE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAChF,QAAQ,CAAC,mBAAmB,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,MAAM,yBAAyB,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE3E,eAAO,MAAM,oBAAoB,yBAAyB,CAAC;AAC3D,eAAO,MAAM,YAAY,iBAAiB,CAAC;AAC3C,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD,eAAO,MAAM,iBAAiB,sBAAsB,CAAC;AACrD,eAAO,MAAM,mBAAmB,wBAAwB,CAAC;AACzD,eAAO,MAAM,eAAe,oBAAoB,CAAC;AAEjD,uFAAuF;AACvF,eAAO,MAAM,sBAAsB,qEAAsE,CAAC;AAC1G,eAAO,MAAM,qBAAqB,sIAGxB,CAAC;AAEX,MAAM,WAAW,mCAAmC;IAClD,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;IAC5C,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC;AAED,eAAO,MAAM,6BAA6B,EAAE,MAAM,CAAC,yBAAyB,EAAE,mCAAmC,CAehH,CAAC;AAEF,MAAM,WAAW,8BAA8B;IAC7C,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,2EAA2E;IAC3E,QAAQ,CAAC,WAAW,EAAE,SAAS,MAAM,EAAE,CAAC;CACzC;AAED,eAAO,MAAM,yBAAyB,kCAAmC,CAAC;AAE1E,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,+BAA+B,GAAG,8BAA8B,CAyFhH;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAQrF"}
|
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
// Self-contained `assets validate-animation` validator: checks that a character's required
|
|
2
2
|
// locomotion/action clips are present in its available clip set (from --clips or the asset
|
|
3
3
|
// manifest's animationClips metadata). No external dep so the CLI boundary stays standalone.
|
|
4
|
+
export const HERO_NOT_A_CHARACTER = "HERO_NOT_A_CHARACTER";
|
|
5
|
+
export const HERO_NO_SKIN = "HERO_NO_SKIN";
|
|
6
|
+
export const HERO_TOO_FEW_JOINTS = "HERO_TOO_FEW_JOINTS";
|
|
7
|
+
export const HERO_MISSING_CLIP = "HERO_MISSING_CLIP";
|
|
8
|
+
export const HERO_CLIP_TOO_SHORT = "HERO_CLIP_TOO_SHORT";
|
|
9
|
+
export const HERO_UNTEXTURED = "HERO_UNTEXTURED";
|
|
10
|
+
/** §6.9 clip set for `template-hero`; `hero-character` needs the locomotion subset. */
|
|
11
|
+
export const HERO_CHARACTER_ACTIONS = ["idle", "walk", "run", "jump-start", "jump-loop", "land"];
|
|
12
|
+
export const TEMPLATE_HERO_ACTIONS = [
|
|
13
|
+
...HERO_CHARACTER_ACTIONS,
|
|
14
|
+
"sprint", "turn-l", "turn-r", "interact", "hit-react", "attack"
|
|
15
|
+
];
|
|
16
|
+
export const ANIMATION_ASSET_HERO_PROFILES = {
|
|
17
|
+
"hero-character": {
|
|
18
|
+
profile: "hero-character",
|
|
19
|
+
minTriangles: 2_000,
|
|
20
|
+
minJoints: 30,
|
|
21
|
+
requiredActions: HERO_CHARACTER_ACTIONS,
|
|
22
|
+
minClipDuration: 0.2
|
|
23
|
+
},
|
|
24
|
+
"template-hero": {
|
|
25
|
+
profile: "template-hero",
|
|
26
|
+
minTriangles: 15_000,
|
|
27
|
+
minJoints: 50,
|
|
28
|
+
requiredActions: TEMPLATE_HERO_ACTIONS,
|
|
29
|
+
minClipDuration: 0.2
|
|
30
|
+
}
|
|
31
|
+
};
|
|
4
32
|
export const DEFAULT_ANIMATION_ACTIONS = ["idle", "walk", "run"];
|
|
5
33
|
export function validateAnimationAssets(options) {
|
|
6
34
|
const requiredActions = options.requiredActions ?? DEFAULT_ANIMATION_ACTIONS;
|
|
@@ -9,6 +37,7 @@ export function validateAnimationAssets(options) {
|
|
|
9
37
|
const messages = [];
|
|
10
38
|
const missingActions = [];
|
|
11
39
|
const missingClips = [];
|
|
40
|
+
const reasonCodes = new Set();
|
|
12
41
|
if (options.requireRig && available.size === 0) {
|
|
13
42
|
failures.push("asset declares no animation clips (expected a rigged/animated character).");
|
|
14
43
|
}
|
|
@@ -26,12 +55,62 @@ export function validateAnimationAssets(options) {
|
|
|
26
55
|
}
|
|
27
56
|
messages.push(`action "${action}" -> "${clip}" OK`);
|
|
28
57
|
}
|
|
58
|
+
const profile = options.profile !== undefined ? ANIMATION_ASSET_HERO_PROFILES[options.profile] : undefined;
|
|
59
|
+
const inspection = options.inspection;
|
|
60
|
+
if (profile !== undefined && inspection !== undefined) {
|
|
61
|
+
// Geometry + texture bar — every code is reported, not just the first.
|
|
62
|
+
if (inspection.triangleCount < profile.minTriangles) {
|
|
63
|
+
reasonCodes.add(HERO_NOT_A_CHARACTER);
|
|
64
|
+
failures.push(`${profile.profile}: ${inspection.triangleCount} triangles < ${profile.minTriangles} (${HERO_NOT_A_CHARACTER}).`);
|
|
65
|
+
}
|
|
66
|
+
if (inspection.skinCount < 1) {
|
|
67
|
+
reasonCodes.add(HERO_NO_SKIN);
|
|
68
|
+
failures.push(`${profile.profile}: no skinned mesh (${HERO_NO_SKIN}).`);
|
|
69
|
+
}
|
|
70
|
+
if (inspection.jointCount < profile.minJoints) {
|
|
71
|
+
reasonCodes.add(HERO_TOO_FEW_JOINTS);
|
|
72
|
+
failures.push(`${profile.profile}: ${inspection.jointCount} joints < ${profile.minJoints} (${HERO_TOO_FEW_JOINTS}).`);
|
|
73
|
+
}
|
|
74
|
+
// Clip coverage against the profile's action set — unmapped actions and
|
|
75
|
+
// absent clips both land under HERO_MISSING_CLIP (the union, deduped).
|
|
76
|
+
const durations = new Map(inspection.clips.map((clip) => [clip.name, clip.duration]));
|
|
77
|
+
let missingClip = false;
|
|
78
|
+
for (const action of profile.requiredActions) {
|
|
79
|
+
const clip = options.clipMap[action];
|
|
80
|
+
if (clip === undefined || clip.trim().length === 0 || !durations.has(clip)) {
|
|
81
|
+
missingClip = true;
|
|
82
|
+
if (!missingActions.includes(action))
|
|
83
|
+
missingActions.push(action);
|
|
84
|
+
if (clip !== undefined && clip.trim().length > 0 && !missingClips.includes(clip))
|
|
85
|
+
missingClips.push(clip);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (missingClip) {
|
|
89
|
+
reasonCodes.add(HERO_MISSING_CLIP);
|
|
90
|
+
failures.push(`${profile.profile}: required action(s) unmapped or clip absent (${HERO_MISSING_CLIP}).`);
|
|
91
|
+
}
|
|
92
|
+
for (const action of profile.requiredActions) {
|
|
93
|
+
const clip = options.clipMap[action];
|
|
94
|
+
if (clip === undefined)
|
|
95
|
+
continue;
|
|
96
|
+
const duration = durations.get(clip);
|
|
97
|
+
if (duration !== undefined && duration < profile.minClipDuration) {
|
|
98
|
+
reasonCodes.add(HERO_CLIP_TOO_SHORT);
|
|
99
|
+
failures.push(`${profile.profile}: clip "${clip}" is ${duration.toFixed(3)} s < ${profile.minClipDuration} s (${HERO_CLIP_TOO_SHORT}).`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (!inspection.hasBaseColorTexture) {
|
|
103
|
+
reasonCodes.add(HERO_UNTEXTURED);
|
|
104
|
+
failures.push(`${profile.profile}: no baseColor texture (${HERO_UNTEXTURED}).`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
29
107
|
return {
|
|
30
108
|
ok: failures.length === 0,
|
|
31
109
|
messages,
|
|
32
110
|
failures,
|
|
33
111
|
missingActions,
|
|
34
|
-
missingClips
|
|
112
|
+
missingClips,
|
|
113
|
+
reasonCodes: [...reasonCodes]
|
|
35
114
|
};
|
|
36
115
|
}
|
|
37
116
|
/** Parse a `--map idle=Idle_Loop,walk=Walk_Loop` style flag into a clip map. */
|