@vvfx/ge-ir 0.0.1-beta.6 → 0.0.1-beta.7

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/dist/index.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  * Description: Galacean Effects and animation IR bidirectional conversion package
4
4
  * Author: Ant Group CO., Ltd.
5
5
  * Contributors: 澄弈
6
- * Version: v0.0.1-beta.6
6
+ * Version: v0.0.1-beta.7
7
7
  */
8
8
 
9
9
  import { IRBlendMode, IRShapePrimitiveType, IRFillType, IRLineCap, IRLineJoin, IREndBehavior, validateIRCompositionOrThrow } from '@vvfx/animation-ir';
@@ -1744,11 +1744,9 @@ function getTimeContext(layer) {
1744
1744
  }
1745
1745
 
1746
1746
  function buildTransformAnimation(layer, ctx) {
1747
- var transform = layer.transform;
1748
- if (transform == null) {
1747
+ if (layer.transform == null) {
1749
1748
  return {};
1750
1749
  }
1751
- var timeContext = getTimeContext(layer);
1752
1750
  // Passthrough: ge2ir stores raw animation data in specific.effects to bypass the
1753
1751
  // IR keyframe conversion pipeline. Raw GE data is used verbatim when
1754
1752
  // available; otherwise the standard IR → GE conversion runs.
@@ -1756,15 +1754,32 @@ function buildTransformAnimation(layer, ctx) {
1756
1754
  var passthroughPosition = effectsSpecific == null ? void 0 : effectsSpecific.positionOverLifetime;
1757
1755
  var passthroughRotation = effectsSpecific == null ? void 0 : effectsSpecific.rotationOverLifetime;
1758
1756
  var passthroughSize = effectsSpecific == null ? void 0 : effectsSpecific.sizeOverLifetime;
1759
- var positionOverLifetime = passthroughPosition != null ? passthroughPosition : buildPositionAnim(layer, transform, timeContext, ctx);
1760
- var rotationOverLifetime = passthroughRotation != null ? passthroughRotation : buildRotationAnim(transform, timeContext);
1761
- var sizeOverLifetime = passthroughSize != null ? passthroughSize : buildSizeAnim(transform, timeContext);
1757
+ var normalized = buildNormalizedTransformAnimation(layer, ctx);
1758
+ var positionOverLifetime = passthroughPosition != null ? passthroughPosition : normalized.positionOverLifetime;
1759
+ var rotationOverLifetime = passthroughRotation != null ? passthroughRotation : normalized.rotationOverLifetime;
1760
+ var sizeOverLifetime = passthroughSize != null ? passthroughSize : normalized.sizeOverLifetime;
1762
1761
  return {
1763
1762
  positionOverLifetime: positionOverLifetime,
1764
1763
  rotationOverLifetime: rotationOverLifetime,
1765
1764
  sizeOverLifetime: sizeOverLifetime
1766
1765
  };
1767
1766
  }
1767
+ /**
1768
+ * Encode normalized IR transform channels as GE timeline payloads without
1769
+ * consulting composition-specific passthrough data. Sibling converters use
1770
+ * this when they need the canonical curve encoding for a preserved sub-scene.
1771
+ */ function buildNormalizedTransformAnimation(layer, ctx) {
1772
+ var transform = layer.transform;
1773
+ if (transform == null) {
1774
+ return {};
1775
+ }
1776
+ var timeContext = getTimeContext(layer);
1777
+ return {
1778
+ positionOverLifetime: buildPositionAnim(layer, transform, timeContext, ctx),
1779
+ rotationOverLifetime: buildRotationAnim(transform, timeContext),
1780
+ sizeOverLifetime: buildSizeAnim(transform, timeContext)
1781
+ };
1782
+ }
1768
1783
  function buildPositionAnim(layer, transform, timeContext, ctx) {
1769
1784
  var _posResult_curves_;
1770
1785
  var _posResult_pathPoints_;
@@ -1972,6 +1987,9 @@ function buildColorAnimation(layer, ir) {
1972
1987
  if (passthroughColor != null) {
1973
1988
  return passthroughColor;
1974
1989
  }
1990
+ return buildNormalizedColorAnimation(layer);
1991
+ }
1992
+ /** Encode normalized IR opacity as a GE color-over-lifetime payload. */ function buildNormalizedColorAnimation(layer) {
1975
1993
  var transform = layer.transform;
1976
1994
  if ((transform == null ? void 0 : transform.opacity) == null) {
1977
1995
  return undefined;
@@ -5684,7 +5702,6 @@ function convertGEToIR(scene, options) {
5684
5702
  }
5685
5703
  function parseItemToLayer(item, itemId, index, ctx) {
5686
5704
  var _item_name, _item_visible, _ref, _item_delay, _ref1, _item_duration, _ref2;
5687
- var _item_transform;
5688
5705
  var name = (_item_name = item['name']) != null ? _item_name : "layer_" + index;
5689
5706
  var GEType = item['type'];
5690
5707
  var visible = (_item_visible = item['visible']) != null ? _item_visible : true;
@@ -5714,6 +5731,14 @@ function parseItemToLayer(item, itemId, index, ctx) {
5714
5731
  }
5715
5732
  // Parse transforms
5716
5733
  var itemTransform = item['transform'];
5734
+ var itemSize = readItemSize(itemTransform);
5735
+ var textBounds = type === 'text' && itemSize == null ? readTextBounds(componentData == null ? void 0 : componentData.text) : undefined;
5736
+ var localBounds = itemSize != null ? {
5737
+ x: 0,
5738
+ y: 0,
5739
+ width: itemSize.x / ctx.ratio,
5740
+ height: itemSize.y / ctx.ratio
5741
+ } : textBounds;
5717
5742
  var transform;
5718
5743
  if (itemTransform != null) {
5719
5744
  var staticChannels = parseStaticTransform(itemTransform, ctx);
@@ -5780,90 +5805,75 @@ function parseItemToLayer(item, itemId, index, ctx) {
5780
5805
  rawColorOverLifetime = col;
5781
5806
  }
5782
5807
  }
5783
- // Anchor from component — default to center (0.5, 0.5) when not explicitly set
5784
- if (type !== 'null') {
5785
- var _item_transform1;
5786
- var itemSize = (_item_transform1 = item['transform']) == null ? void 0 : _item_transform1['size'];
5787
- if (itemSize != null) {
5788
- var _ref3;
5789
- var layerWidth = itemSize.x / ctx.ratio;
5790
- var layerHeight = itemSize.y / ctx.ratio;
5791
- var anchorScale = (_ref3 = componentData == null ? void 0 : componentData.anchorScale) != null ? _ref3 : [
5792
- 0.5,
5793
- 0.5
5808
+ // Anchor from component — default to center (0.5, 0.5) when not explicitly set.
5809
+ // Some GE text has no transform.size, so its bounds come from TextComponent.options.
5810
+ // The anchor itself still follows the same normalized renderer coordinates as every
5811
+ // other visual layer; text alignment and glyph baseline are renderer-internal details.
5812
+ if (type !== 'null' && localBounds != null) {
5813
+ var _ref3;
5814
+ var layerWidth = localBounds.width;
5815
+ var layerHeight = localBounds.height;
5816
+ var anchorScale = (_ref3 = componentData == null ? void 0 : componentData.anchorScale) != null ? _ref3 : [
5817
+ 0.5,
5818
+ 0.5
5819
+ ];
5820
+ var anchorInfo = reverseGenericAnchor(anchorScale, layerWidth, layerHeight);
5821
+ var anchorX = anchorInfo.anchorX, anchorY = anchorInfo.anchorY, anchorOffsetX = anchorInfo.anchorOffsetX, anchorOffsetY = anchorInfo.anchorOffsetY;
5822
+ if (transform == null) {
5823
+ transform = {};
5824
+ }
5825
+ transform.anchor = {
5826
+ keyframed: false,
5827
+ value: [
5828
+ anchorX,
5829
+ anchorY,
5830
+ 0
5831
+ ]
5832
+ };
5833
+ // Reverse the position adjustments ir2ge's processVisualLayer re-applies
5834
+ // for non-centered anchors, so they don't double-apply on round-trip.
5835
+ // Forward order (in 2D-px equivalent): pos += anchorOffset (computeStaticPosition),
5836
+ // then pos += scaleAdjust (applyScalePositionAdjust). We subtract both.
5837
+ var pos = transform.position;
5838
+ if (pos != null && !pos.keyframed && pos.value != null) {
5839
+ var _scale_, _scale_1;
5840
+ var _transform_scale;
5841
+ // scaleAdjust (only when static scale != 1 and anchor off-center by >0.5px):
5842
+ // 3D: x += anchorDiffX*(1-sx)*ratio ; y -= anchorDiffY*(1-sy)*ratio
5843
+ // In 2D-px (÷ratio, y-axis flips sign): x2d += anchorDiffX*(1-sx) ;
5844
+ // y2d += anchorDiffY*(1-sy) (the two sign flips cancel).
5845
+ var scale = ((_transform_scale = transform.scale) == null ? void 0 : _transform_scale.keyframed) === false && Array.isArray(transform.scale.value) ? transform.scale.value : [
5846
+ 1,
5847
+ 1,
5848
+ 1
5794
5849
  ];
5795
- var anchorX = anchorScale[0] * layerWidth;
5796
- var anchorY = anchorScale[1] * layerHeight;
5797
- if (transform == null) {
5798
- transform = {};
5850
+ var sx = (_scale_ = scale[0]) != null ? _scale_ : 1;
5851
+ var sy = (_scale_1 = scale[1]) != null ? _scale_1 : 1;
5852
+ var anchorDiffX = anchorX - layerWidth / 2;
5853
+ var anchorDiffY = anchorY - layerHeight / 2;
5854
+ var anchorOffCenter = Math.abs(anchorDiffX) > 0.5 || Math.abs(anchorDiffY) > 0.5;
5855
+ var hasStaticScale = !(sx === 1 && sy === 1);
5856
+ var scaleAdjustX = 0;
5857
+ var scaleAdjustY = 0;
5858
+ if (hasStaticScale && anchorOffCenter && layerWidth > 0 && layerHeight > 0) {
5859
+ scaleAdjustX = anchorDiffX * (1 - sx);
5860
+ scaleAdjustY = anchorDiffY * (1 - sy);
5799
5861
  }
5800
- transform.anchor = {
5801
- keyframed: false,
5802
- value: [
5803
- anchorX,
5804
- anchorY,
5805
- 0
5806
- ]
5807
- };
5808
- // Reverse the position adjustments ir2ge's processVisualLayer re-applies
5809
- // for non-centered anchors, so they don't double-apply on round-trip.
5810
- // Forward order (in 2D-px equivalent): pos += anchorOffset (computeStaticPosition),
5811
- // then pos += scaleAdjust (applyScalePositionAdjust). We subtract both.
5812
- var pos = transform.position;
5813
- if (pos != null && !pos.keyframed && pos.value != null) {
5814
- var _scale_, _scale_1;
5815
- var _transform_scale;
5816
- // anchorOffset = -(anchor - size/2), added to the raw 2D position.
5817
- var anchorOffsetX = -(anchorX - layerWidth / 2);
5818
- var anchorOffsetY = -(anchorY - layerHeight / 2);
5819
- // scaleAdjust (only when static scale != 1 and anchor off-center by >0.5px):
5820
- // 3D: x += anchorDiffX*(1-sx)*ratio ; y -= anchorDiffY*(1-sy)*ratio
5821
- // In 2D-px (÷ratio, y-axis flips sign): x2d += anchorDiffX*(1-sx) ;
5822
- // y2d += anchorDiffY*(1-sy) (the two sign flips cancel).
5823
- var scale = ((_transform_scale = transform.scale) == null ? void 0 : _transform_scale.keyframed) === false && Array.isArray(transform.scale.value) ? transform.scale.value : [
5824
- 1,
5825
- 1,
5826
- 1
5827
- ];
5828
- var sx = (_scale_ = scale[0]) != null ? _scale_ : 1;
5829
- var sy = (_scale_1 = scale[1]) != null ? _scale_1 : 1;
5830
- var anchorDiffX = anchorX - layerWidth / 2;
5831
- var anchorDiffY = anchorY - layerHeight / 2;
5832
- var anchorOffCenter = Math.abs(anchorDiffX) > 0.5 || Math.abs(anchorDiffY) > 0.5;
5833
- var hasStaticScale = !(sx === 1 && sy === 1);
5834
- var scaleAdjustX = 0;
5835
- var scaleAdjustY = 0;
5836
- if (hasStaticScale && anchorOffCenter && layerWidth > 0 && layerHeight > 0) {
5837
- scaleAdjustX = anchorDiffX * (1 - sx);
5838
- scaleAdjustY = anchorDiffY * (1 - sy);
5839
- }
5840
- var totalX = anchorOffsetX + scaleAdjustX;
5841
- var totalY = anchorOffsetY + scaleAdjustY;
5842
- if (Math.abs(totalX) > 1e-6 || Math.abs(totalY) > 1e-6) {
5843
- var _pos_value_;
5844
- transform.position = {
5845
- keyframed: false,
5846
- value: [
5847
- pos.value[0] - totalX,
5848
- pos.value[1] - totalY,
5849
- (_pos_value_ = pos.value[2]) != null ? _pos_value_ : 0
5850
- ]
5851
- };
5852
- }
5862
+ var totalX = anchorOffsetX + scaleAdjustX;
5863
+ var totalY = anchorOffsetY + scaleAdjustY;
5864
+ if (Math.abs(totalX) > 1e-6 || Math.abs(totalY) > 1e-6) {
5865
+ var _pos_value_;
5866
+ transform.position = {
5867
+ keyframed: false,
5868
+ value: [
5869
+ pos.value[0] - totalX,
5870
+ pos.value[1] - totalY,
5871
+ (_pos_value_ = pos.value[2]) != null ? _pos_value_ : 0
5872
+ ]
5873
+ };
5853
5874
  }
5854
5875
  }
5855
5876
  }
5856
- // Layer-local bounds from item transform.size
5857
- var localBounds;
5858
- var itemSize1 = (_item_transform = item['transform']) == null ? void 0 : _item_transform['size'];
5859
- if (itemSize1 != null && itemSize1.x > 0 && itemSize1.y > 0) {
5860
- localBounds = {
5861
- x: 0,
5862
- y: 0,
5863
- width: itemSize1.x / ctx.ratio,
5864
- height: itemSize1.y / ctx.ratio
5865
- };
5866
- }
5867
5877
  var text = (componentData == null ? void 0 : componentData.text) == null ? undefined : _extends({}, componentData.text);
5868
5878
  var solidColor = type === 'solid' ? (_ref2 = componentData == null ? void 0 : componentData.solidColor) != null ? _ref2 : [
5869
5879
  1,
@@ -5950,6 +5960,38 @@ function cloneJson(value) {
5950
5960
  function isRecord(value) {
5951
5961
  return value != null && (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object' && !Array.isArray(value);
5952
5962
  }
5963
+ function readItemSize(itemTransform) {
5964
+ var size = itemTransform == null ? void 0 : itemTransform['size'];
5965
+ if (!isRecord(size)) {
5966
+ return undefined;
5967
+ }
5968
+ var x = size['x'];
5969
+ var y = size['y'];
5970
+ return typeof x === 'number' && Number.isFinite(x) && x > 0 && typeof y === 'number' && Number.isFinite(y) && y > 0 ? {
5971
+ x: x,
5972
+ y: y
5973
+ } : undefined;
5974
+ }
5975
+ function readTextBounds(text) {
5976
+ var width = text == null ? void 0 : text.width;
5977
+ var height = text == null ? void 0 : text.height;
5978
+ return typeof width === 'number' && Number.isFinite(width) && width > 0 && typeof height === 'number' && Number.isFinite(height) && height > 0 ? {
5979
+ x: 0,
5980
+ y: 0,
5981
+ width: width,
5982
+ height: height
5983
+ } : undefined;
5984
+ }
5985
+ function reverseGenericAnchor(anchorScale, width, height) {
5986
+ var anchorX = anchorScale[0] * width;
5987
+ var anchorY = anchorScale[1] * height;
5988
+ return {
5989
+ anchorX: anchorX,
5990
+ anchorY: anchorY,
5991
+ anchorOffsetX: -(anchorX - width / 2),
5992
+ anchorOffsetY: -(anchorY - height / 2)
5993
+ };
5994
+ }
5953
5995
 
5954
5996
  /**
5955
5997
  * Read-side accessors for the `IRLayerNode.specific.lottie` slot.
@@ -5964,5 +6006,5 @@ function isRecord(value) {
5964
6006
  return (_layer_specific = layer.specific) == null ? void 0 : _layer_specific.lottie;
5965
6007
  }
5966
6008
 
5967
- export { DEFAULT_CAMERA_FOV, DEFAULT_CAMERA_Z, DEFAULT_CLIP_MODE, assembleScene, buildTimelineTracks, convert2dTo3dPoint, convertGEToIR, convertIRToGE, createId, estimateTextWidth, get2dTo3dRatio, getEffectsCompositionSpecific, getEffectsLayerSpecific, hasEffectsAnimationPassthrough, hasEffectsColorAnimationPassthrough, hasIndependentParentLifetime, invalidateEffectsLayerSpecific, irPositionKeyframesToGE, irScalarKeyframesToGE, irVectorKeyframesToGE, lerp, normalizeChildVisibilityByParentDelays, readLottieSpecific, roundNumber, shouldUseKeyframeMode, toDataPath };
6009
+ export { DEFAULT_CAMERA_FOV, DEFAULT_CAMERA_Z, DEFAULT_CLIP_MODE, assembleScene, buildNormalizedColorAnimation, buildNormalizedTransformAnimation, buildTimelineTracks, convert2dTo3dPoint, convertGEToIR, convertIRToGE, createId, estimateTextWidth, get2dTo3dRatio, getEffectsCompositionSpecific, getEffectsLayerSpecific, hasEffectsAnimationPassthrough, hasEffectsColorAnimationPassthrough, hasIndependentParentLifetime, invalidateEffectsLayerSpecific, irPositionKeyframesToGE, irScalarKeyframesToGE, irVectorKeyframesToGE, lerp, normalizeChildVisibilityByParentDelays, readLottieSpecific, roundNumber, shouldUseKeyframeMode, toDataPath };
5968
6010
  //# sourceMappingURL=index.mjs.map