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