@aura3d/assets 2.0.3 → 3.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.
Files changed (38) hide show
  1. package/dist/GLTFAnimationRuntime.d.ts +95 -2
  2. package/dist/GLTFAnimationRuntime.d.ts.map +1 -1
  3. package/dist/GLTFAnimationRuntime.js +328 -3
  4. package/dist/GLTFAnimationRuntime.js.map +1 -1
  5. package/dist/GLTFExtensionSupport.js +2 -2
  6. package/dist/GLTFExtensionSupport.js.map +1 -1
  7. package/dist/GLTFLoader.d.ts +360 -1
  8. package/dist/GLTFLoader.d.ts.map +1 -1
  9. package/dist/GLTFLoader.js +197 -1
  10. package/dist/GLTFLoader.js.map +1 -1
  11. package/dist/KTX2BasisTextureTranscoder.d.ts +39 -0
  12. package/dist/KTX2BasisTextureTranscoder.d.ts.map +1 -1
  13. package/dist/KTX2BasisTextureTranscoder.js +70 -0
  14. package/dist/KTX2BasisTextureTranscoder.js.map +1 -1
  15. package/dist/TexturePipeline.d.ts +20 -0
  16. package/dist/TexturePipeline.d.ts.map +1 -1
  17. package/dist/TexturePipeline.js +20 -0
  18. package/dist/TexturePipeline.js.map +1 -1
  19. package/dist/TextureStreaming.d.ts +30 -0
  20. package/dist/TextureStreaming.d.ts.map +1 -1
  21. package/dist/TextureStreaming.js +53 -0
  22. package/dist/TextureStreaming.js.map +1 -1
  23. package/dist/browser-index.d.ts +7 -3
  24. package/dist/browser-index.d.ts.map +1 -1
  25. package/dist/browser-index.js +3 -1
  26. package/dist/browser-index.js.map +1 -1
  27. package/dist/gltf-runtime.d.ts +1 -1
  28. package/dist/gltf-runtime.d.ts.map +1 -1
  29. package/dist/gltf-runtime.js.map +1 -1
  30. package/dist/index.d.ts +7 -7
  31. package/dist/index.d.ts.map +1 -1
  32. package/dist/index.js +3 -3
  33. package/dist/index.js.map +1 -1
  34. package/dist/loaders/HDRLoader.d.ts +40 -0
  35. package/dist/loaders/HDRLoader.d.ts.map +1 -1
  36. package/dist/loaders/HDRLoader.js +158 -0
  37. package/dist/loaders/HDRLoader.js.map +1 -1
  38. package/package.json +4 -4
@@ -986,6 +986,40 @@ function resolveTextureInfo(textures, info, label) {
986
986
  function usesGLTFExtension(json, extension) {
987
987
  return Boolean(json.extensionsRequired?.includes(extension) || json.extensionsUsed?.includes(extension));
988
988
  }
989
+ /**
990
+ * Save step: validate a variant switch against the loaded variant list and produce the
991
+ * persisted scene-state JSON value. Throws naming the variant when it is not defined —
992
+ * no silent no-ops.
993
+ */
994
+ export function serializeMaterialVariantSelection(selectedVariant, materialVariants) {
995
+ if (selectedVariant !== undefined) {
996
+ validateSceneMaterialVariant(materialVariants, selectedVariant);
997
+ }
998
+ return selectedVariant === undefined
999
+ ? { schemaVersion: "gltf-material-variant-state" }
1000
+ : { schemaVersion: "gltf-material-variant-state", selectedVariant };
1001
+ }
1002
+ /**
1003
+ * Reload step: parse persisted scene-state JSON back into a selection the loader's scene
1004
+ * options (`selectedVariant`) accept. Throws on schema mismatch or unknown variant names.
1005
+ */
1006
+ export function parseMaterialVariantSelection(state, materialVariants) {
1007
+ if (typeof state !== "object" || state === null) {
1008
+ throw new Error("glTF material variant scene state must be an object.");
1009
+ }
1010
+ const record = state;
1011
+ if (record.schemaVersion !== "gltf-material-variant-state") {
1012
+ throw new Error("glTF material variant scene state has an unsupported schemaVersion.");
1013
+ }
1014
+ const selectedVariant = record.selectedVariant;
1015
+ if (selectedVariant === undefined)
1016
+ return undefined;
1017
+ if (typeof selectedVariant !== "string") {
1018
+ throw new Error("glTF material variant scene state selectedVariant must be a string.");
1019
+ }
1020
+ validateSceneMaterialVariant(materialVariants, selectedVariant);
1021
+ return selectedVariant;
1022
+ }
989
1023
  function usesGLTFMeshoptExtension(json) {
990
1024
  return GLTF_MESHOPT_EXTENSION_NAMES.some((extension) => usesGLTFExtension(json, extension));
991
1025
  }
@@ -1574,7 +1608,22 @@ function createAnimationClips(json, buffers, accessorCache) {
1574
1608
  throw new Error(`glTF animation ${animationIndex} channel ${channelIndex} references missing sampler ${channel.sampler}`);
1575
1609
  }
1576
1610
  if (isOptionalAnimationPointerChannel(json, channel)) {
1577
- return [];
1611
+ const pointer = channel.target.extensions?.KHR_animation_pointer?.pointer ?? "";
1612
+ const resolved = resolveAnimationPointerBinding(json, pointer);
1613
+ if (!resolved) {
1614
+ // Unsupported pointer shape: preserve the previous diagnose-and-drop behavior
1615
+ // rather than failing the whole asset. Supported shapes are bound below.
1616
+ return [];
1617
+ }
1618
+ const interpolation = resolveAnimationInterpolation(sampler.interpolation, animationIndex, channelIndex);
1619
+ const times = readAccessor(json, buffers, sampler.input, accessorCache).map((row) => row[0] ?? 0);
1620
+ const output = readAccessor(json, buffers, sampler.output, accessorCache);
1621
+ const values = animationPointerKeyframesForSampler(resolved.valueType, times, output, interpolation, animationIndex, channelIndex);
1622
+ return [new AnimationTrack({
1623
+ target: resolved.target,
1624
+ valueType: resolved.valueType,
1625
+ keyframes: values
1626
+ })];
1578
1627
  }
1579
1628
  if (channel.target.node === undefined || !json.nodes?.[channel.target.node]) {
1580
1629
  throw new Error(`glTF animation ${animationIndex} channel ${channelIndex} references missing target node ${channel.target.node ?? "undefined"}`);
@@ -1600,6 +1649,153 @@ function isOptionalAnimationPointerChannel(json, channel) {
1600
1649
  json.extensionsRequired?.includes("KHR_animation_pointer") !== true &&
1601
1650
  typeof channel.target.extensions?.KHR_animation_pointer?.pointer === "string";
1602
1651
  }
1652
+ export function resolveAnimationPointerBinding(json, pointer) {
1653
+ const segments = pointer.split("/").filter((segment) => segment.length > 0);
1654
+ if (segments.length < 3)
1655
+ return undefined;
1656
+ // Full extension-object form first: it carries no bare index in segment 2.
1657
+ if (segments[0] === "extensions" && segments[1] === "KHR_lights_punctual" && segments[2] === "lights") {
1658
+ return resolvePunctualLightPointer(json, pointer, segments.slice(3));
1659
+ }
1660
+ const [root, indexRaw, ...rest] = segments;
1661
+ const index = Number(indexRaw);
1662
+ if (!Number.isInteger(index) || index < 0)
1663
+ return undefined;
1664
+ if (root === "nodes") {
1665
+ const node = json.nodes?.[index];
1666
+ if (!node)
1667
+ return undefined;
1668
+ const name = typeof node.name === "string" && node.name.trim().length > 0 ? node.name : `node-${index}`;
1669
+ const [leaf] = rest;
1670
+ if (leaf === "translation" || leaf === "scale") {
1671
+ return { pointer, target: `${name}.${leaf}`, valueType: "vector3" };
1672
+ }
1673
+ if (leaf === "rotation") {
1674
+ return { pointer, target: `${name}.${leaf}`, valueType: "quaternion" };
1675
+ }
1676
+ if (leaf === "weights" && rest.length === 1) {
1677
+ return { pointer, target: `${name}.weights`, valueType: "number-array" };
1678
+ }
1679
+ return undefined;
1680
+ }
1681
+ if (root === "meshes") {
1682
+ const mesh = json.meshes?.[index];
1683
+ if (!mesh)
1684
+ return undefined;
1685
+ const meshName = typeof mesh.name === "string" && (mesh.name?.trim().length ?? 0) > 0
1686
+ ? mesh.name
1687
+ : `mesh-${index}`;
1688
+ if (rest.length === 1 && rest[0] === "weights") {
1689
+ return { pointer, target: `${meshName}.weights`, valueType: "number-array" };
1690
+ }
1691
+ return undefined;
1692
+ }
1693
+ if (root === "materials") {
1694
+ const material = json.materials?.[index];
1695
+ if (!material)
1696
+ return undefined;
1697
+ const materialName = typeof material.name === "string" && material.name.trim().length > 0 ? material.name : `material-${index}`;
1698
+ if (rest.length === 0)
1699
+ return undefined;
1700
+ const leaf = rest[rest.length - 1] ?? "";
1701
+ return { pointer, target: `material:${materialName}.${rest.join(".")}`, valueType: pointerLeafValueType(leaf) };
1702
+ }
1703
+ if (root === "lights") {
1704
+ return resolvePunctualLightPointer(json, pointer, segments.slice(1));
1705
+ }
1706
+ return undefined;
1707
+ }
1708
+ function resolvePunctualLightPointer(json, pointer, lightSegments) {
1709
+ const [lightIndexRaw, ...lightRest] = lightSegments;
1710
+ const lightIndex = Number(lightIndexRaw);
1711
+ if (!Number.isInteger(lightIndex) || lightIndex < 0 || lightRest.length === 0)
1712
+ return undefined;
1713
+ const light = json.extensions?.KHR_lights_punctual?.lights?.[lightIndex];
1714
+ if (!light)
1715
+ return undefined;
1716
+ const lightName = typeof light.name === "string" && light.name.trim().length > 0 ? light.name : `light-${lightIndex}`;
1717
+ const leaf = lightRest[lightRest.length - 1] ?? "";
1718
+ if (leaf !== "intensity" && leaf !== "color" && leaf !== "range")
1719
+ return undefined;
1720
+ return { pointer, target: `light:${lightName}.${lightRest.join(".")}`, valueType: leaf === "color" ? "vector3" : "scalar" };
1721
+ }
1722
+ const POINTER_SCALAR_LEAVES = new Set([
1723
+ "intensity",
1724
+ "range",
1725
+ "alphaCutoff",
1726
+ "metallicFactor",
1727
+ "roughnessFactor",
1728
+ "normalScale",
1729
+ "occlusionStrength",
1730
+ "emissiveStrength",
1731
+ "clearcoatFactor",
1732
+ "clearcoatRoughnessFactor",
1733
+ "transmissionFactor",
1734
+ "thicknessFactor",
1735
+ "attenuationDistance",
1736
+ "ior",
1737
+ "specularFactor",
1738
+ "sheenRoughnessFactor",
1739
+ "iridescenceFactor",
1740
+ "iridescenceIor",
1741
+ "dispersion"
1742
+ ]);
1743
+ const POINTER_VEC3_LEAVES = new Set([
1744
+ "translation",
1745
+ "scale",
1746
+ "color",
1747
+ "emissiveFactor",
1748
+ "attenuationColor",
1749
+ "specularColorFactor",
1750
+ "sheenColorFactor"
1751
+ ]);
1752
+ function pointerLeafValueType(leaf) {
1753
+ if (POINTER_SCALAR_LEAVES.has(leaf))
1754
+ return "scalar";
1755
+ if (POINTER_VEC3_LEAVES.has(leaf))
1756
+ return "vector3";
1757
+ if (leaf === "rotation")
1758
+ return "quaternion";
1759
+ // baseColorFactor (vec4), packed factors, and unknown leaves interpolate elementwise.
1760
+ return "number-array";
1761
+ }
1762
+ function animationPointerKeyframesForSampler(valueType, times, output, interpolation, animationIndex, channelIndex) {
1763
+ const convert = (row) => {
1764
+ if (valueType === "scalar")
1765
+ return row[0] ?? 0;
1766
+ if (valueType === "vector3")
1767
+ return toVec3(row);
1768
+ if (valueType === "quaternion")
1769
+ return toQuat(row);
1770
+ return [...row];
1771
+ };
1772
+ if (interpolation !== "CUBICSPLINE") {
1773
+ if (times.length !== output.length) {
1774
+ throw new Error(`glTF animation ${animationIndex} channel ${channelIndex} input/output count mismatch`);
1775
+ }
1776
+ const samples = sanitizeAnimationSamples(times, output, 1);
1777
+ const mode = interpolation === "STEP" ? "step" : "linear";
1778
+ return samples.times.map((time, index) => ({
1779
+ time,
1780
+ value: convert(samples.output[index]),
1781
+ interpolation: mode
1782
+ }));
1783
+ }
1784
+ if (output.length !== times.length * 3) {
1785
+ throw new Error(`glTF animation ${animationIndex} channel ${channelIndex} CUBICSPLINE output count must be three times input count`);
1786
+ }
1787
+ const samples = sanitizeAnimationSamples(times, output, 3);
1788
+ return samples.times.map((time, index) => {
1789
+ const offset = index * 3;
1790
+ return {
1791
+ time,
1792
+ inTangent: convert(samples.output[offset]),
1793
+ value: convert(samples.output[offset + 1]),
1794
+ outTangent: convert(samples.output[offset + 2]),
1795
+ interpolation: "cubicspline"
1796
+ };
1797
+ });
1798
+ }
1603
1799
  function resolveAnimationInterpolation(value, animationIndex, channelIndex) {
1604
1800
  if (value === undefined || value === "LINEAR" || value === "STEP" || value === "CUBICSPLINE") {
1605
1801
  return value ?? "LINEAR";