@vvfx/ge-ir 0.0.1-beta.5 → 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.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.5
6
+ * Version: v0.0.1-beta.7
7
7
  */
8
8
 
9
9
  'use strict';
@@ -62,6 +62,92 @@ function _create_for_of_iterator_helper_loose(o, allowArrayLike) {
62
62
  throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
63
63
  }
64
64
 
65
+ /** Read GE layer passthrough data. */ function getEffectsLayerSpecific(ir, layer) {
66
+ var _layer_specific;
67
+ return ir.source === 'effects' ? (_layer_specific = layer.specific) == null ? void 0 : _layer_specific.effects : undefined;
68
+ }
69
+ /** Read GE composition passthrough data. */ function getEffectsCompositionSpecific(ir) {
70
+ var _ir_specific;
71
+ return ir.source === 'effects' ? (_ir_specific = ir.specific) == null ? void 0 : _ir_specific.effects : undefined;
72
+ }
73
+ var EFFECTS_ANIMATION_SPECIFIC_KEYS = [
74
+ 'positionOverLifetime',
75
+ 'rotationOverLifetime',
76
+ 'sizeOverLifetime',
77
+ 'colorOverLifetime'
78
+ ];
79
+ var KEYS_BY_INVALIDATION_TARGET = {
80
+ position: [
81
+ 'positionOverLifetime'
82
+ ],
83
+ rotation: [
84
+ 'rotationOverLifetime',
85
+ 'sourceHierarchy'
86
+ ],
87
+ scale: [
88
+ 'sizeOverLifetime',
89
+ 'sourceHierarchy'
90
+ ],
91
+ color: [
92
+ 'colorOverLifetime'
93
+ ],
94
+ opacity: [
95
+ 'colorOverLifetime'
96
+ ],
97
+ anchor: [
98
+ 'sourceHierarchy'
99
+ ],
100
+ mask: [
101
+ 'mask'
102
+ ],
103
+ precomp: [
104
+ 'precompRefId',
105
+ 'precompContent'
106
+ ]
107
+ };
108
+ /**
109
+ * Remove raw GE values that would otherwise shadow an edited normalized field.
110
+ * Empty `effects` and `specific` containers are pruned so serialization stays clean.
111
+ */ function invalidateEffectsLayerSpecific(layer, target) {
112
+ var _layer_specific;
113
+ var effects = (_layer_specific = layer.specific) == null ? void 0 : _layer_specific.effects;
114
+ if (effects == null) {
115
+ return [];
116
+ }
117
+ var removed = [];
118
+ for(var _iterator = _create_for_of_iterator_helper_loose(KEYS_BY_INVALIDATION_TARGET[target]), _step; !(_step = _iterator()).done;){
119
+ var key = _step.value;
120
+ if (key in effects) {
121
+ delete effects[key];
122
+ removed.push(key);
123
+ }
124
+ }
125
+ if (Object.keys(effects).length === 0 && layer.specific != null) {
126
+ delete layer.specific.effects;
127
+ }
128
+ if (layer.specific != null && Object.keys(layer.specific).length === 0) {
129
+ delete layer.specific;
130
+ }
131
+ return removed;
132
+ }
133
+ /** Whether invalidating opacity would also discard a GE color animation. */ function hasEffectsColorAnimationPassthrough(layer) {
134
+ var _layer_specific_effects, _layer_specific;
135
+ var color = (_layer_specific = layer.specific) == null ? void 0 : (_layer_specific_effects = _layer_specific.effects) == null ? void 0 : _layer_specific_effects.colorOverLifetime;
136
+ if (color == null) {
137
+ return false;
138
+ }
139
+ return Object.keys(color).some(function(channelKey) {
140
+ return channelKey !== 'opacity';
141
+ });
142
+ }
143
+ /** Whether the layer retains any raw GE animation payload. */ function hasEffectsAnimationPassthrough(layer) {
144
+ var _layer_specific;
145
+ var effects = (_layer_specific = layer.specific) == null ? void 0 : _layer_specific.effects;
146
+ return effects != null && EFFECTS_ANIMATION_SPECIFIC_KEYS.some(function(key) {
147
+ return effects[key] != null;
148
+ });
149
+ }
150
+
65
151
  var DEFAULT_CAMERA_Z = 8;
66
152
  var DEFAULT_CAMERA_FOV = 60;
67
153
  var DEFAULT_CLIP_MODE = 1;
@@ -1195,36 +1281,29 @@ function getScalarValue(keyframe, dimensionIndex) {
1195
1281
  for(var i = 0; i < keyframes.length; i++){
1196
1282
  var _kf_outTangent, _kf_inTangent;
1197
1283
  var kf = keyframes[i];
1198
- var normalizedT = normalizeTime(kf.t, timeContext.startFrame, timeContext.endFrame);
1284
+ var normalizedT = normalizeTime(kf.frame, timeContext.startFrame, timeContext.endFrame);
1199
1285
  timingCurvePoints.push({
1200
1286
  t: normalizedT,
1201
1287
  outTangent: (_kf_outTangent = kf.outTangent) != null ? _kf_outTangent : DEFAULT_OUT_TANGENT,
1202
1288
  inTangent: (_kf_inTangent = kf.inTangent) != null ? _kf_inTangent : DEFAULT_IN_TANGENT
1203
1289
  });
1204
1290
  if (i < keyframes.length - 1) {
1205
- var _kf_value, _kf_endValue, _nextKf_value, _startPos_, _startPos_1, _stitchEnd_, _stitchEnd_1;
1291
+ var _kf_value, _ref, _kf_endValue, _startPos_, _startPos_1, _segmentEnd_, _segmentEnd_1;
1206
1292
  var nextKf = keyframes[i + 1];
1207
1293
  var startPos = (_kf_value = kf.value) != null ? _kf_value : [
1208
1294
  0,
1209
1295
  0,
1210
1296
  0
1211
1297
  ];
1212
- // Lottie segment end value: kf.endValue is authoritative; falls back to kf.value (mirrors master's `e ?? s`).
1213
- // nextKf.value is only used later in the path-fixup pass to stitch adjacent segments.
1214
- var segmentEnd = kf.hold === true ? startPos : (_kf_endValue = kf.endValue) != null ? _kf_endValue : startPos;
1215
- var stitchEnd = kf.hold === true ? startPos : (_nextKf_value = nextKf.value) != null ? _nextKf_value : [
1216
- 0,
1217
- 0,
1218
- 0
1219
- ];
1298
+ var segmentEnd = kf.hold === true ? startPos : (_ref = (_kf_endValue = kf.endValue) != null ? _kf_endValue : nextKf.value) != null ? _ref : startPos;
1220
1299
  pathPoints.push([
1221
1300
  [
1222
1301
  (_startPos_ = startPos[0]) != null ? _startPos_ : 0,
1223
1302
  (_startPos_1 = startPos[1]) != null ? _startPos_1 : 0
1224
1303
  ],
1225
1304
  [
1226
- (_stitchEnd_ = stitchEnd[0]) != null ? _stitchEnd_ : 0,
1227
- (_stitchEnd_1 = stitchEnd[1]) != null ? _stitchEnd_1 : 0
1305
+ (_segmentEnd_ = segmentEnd[0]) != null ? _segmentEnd_ : 0,
1306
+ (_segmentEnd_1 = segmentEnd[1]) != null ? _segmentEnd_1 : 0
1228
1307
  ]
1229
1308
  ]);
1230
1309
  // Spatial control points (per IRKeyframe convention): outgoing CP from
@@ -1243,11 +1322,11 @@ function getScalarValue(keyframe, dimensionIndex) {
1243
1322
  (_nextKf_spatialIn_1 = nextKf.spatialIn[1]) != null ? _nextKf_spatialIn_1 : 0
1244
1323
  ];
1245
1324
  } else {
1246
- var _startPos_2, _startPos_3, _segmentEnd_, _segmentEnd_1;
1325
+ var _startPos_2, _startPos_3, _segmentEnd_2, _segmentEnd_3;
1247
1326
  var sx = (_startPos_2 = startPos[0]) != null ? _startPos_2 : 0;
1248
1327
  var sy = (_startPos_3 = startPos[1]) != null ? _startPos_3 : 0;
1249
- var ex = (_segmentEnd_ = segmentEnd[0]) != null ? _segmentEnd_ : 0;
1250
- var ey = (_segmentEnd_1 = segmentEnd[1]) != null ? _segmentEnd_1 : 0;
1328
+ var ex = (_segmentEnd_2 = segmentEnd[0]) != null ? _segmentEnd_2 : 0;
1329
+ var ey = (_segmentEnd_3 = segmentEnd[1]) != null ? _segmentEnd_3 : 0;
1251
1330
  toPoint = [
1252
1331
  -sx / 3 + ex / 3,
1253
1332
  -sy / 3 + ey / 3
@@ -1263,10 +1342,6 @@ function getScalarValue(keyframe, dimensionIndex) {
1263
1342
  ]);
1264
1343
  }
1265
1344
  }
1266
- // Fix up path points: adjacent segments should share endpoints
1267
- for(var i1 = 0; i1 < pathPoints.length - 1; i1++){
1268
- pathPoints[i1][1] = pathPoints[i1 + 1][0];
1269
- }
1270
1345
  // Prepend a static segment if the first keyframe doesn't start at t=0.
1271
1346
  // The bridge segment runs synthetic-at-t=0 → original-kf[0]; for it to be a
1272
1347
  // flat hold the END-side tangent (which `buildPositionTimingCurves` reads as
@@ -1275,7 +1350,7 @@ function getScalarValue(keyframe, dimensionIndex) {
1275
1350
  // the IR convention leaves a first-kf inTangent undefined, or whatever the
1276
1351
  // producer set as a no-op).
1277
1352
  if (timingCurvePoints.length > 0 && timingCurvePoints[0].t > 0) {
1278
- var _ref, _ref1;
1353
+ var _ref1, _ref2;
1279
1354
  var _pathPoints_, _pathPoints_1;
1280
1355
  timingCurvePoints[0].inTangent = {
1281
1356
  x: 1,
@@ -1293,11 +1368,11 @@ function getScalarValue(keyframe, dimensionIndex) {
1293
1368
  }
1294
1369
  });
1295
1370
  pathPoints.unshift([
1296
- (_ref = (_pathPoints_ = pathPoints[0]) == null ? void 0 : _pathPoints_[0]) != null ? _ref : [
1371
+ (_ref1 = (_pathPoints_ = pathPoints[0]) == null ? void 0 : _pathPoints_[0]) != null ? _ref1 : [
1297
1372
  0,
1298
1373
  0
1299
1374
  ],
1300
- (_ref1 = (_pathPoints_1 = pathPoints[0]) == null ? void 0 : _pathPoints_1[0]) != null ? _ref1 : [
1375
+ (_ref2 = (_pathPoints_1 = pathPoints[0]) == null ? void 0 : _pathPoints_1[0]) != null ? _ref2 : [
1301
1376
  0,
1302
1377
  0
1303
1378
  ]
@@ -1374,10 +1449,13 @@ function buildCurveForDimension(keyframes, timeContext, dimensionIndex) {
1374
1449
  var _kf_outTangent, _nextKf_inTangent;
1375
1450
  var kf = keyframes[i];
1376
1451
  var nextKf = keyframes[i + 1];
1377
- var t0 = normalizeTime(kf.t, timeContext.startFrame, timeContext.endFrame);
1378
- var t1 = normalizeTime(nextKf.t, timeContext.startFrame, timeContext.endFrame);
1452
+ var t0 = normalizeTime(kf.frame, timeContext.startFrame, timeContext.endFrame);
1453
+ var t1 = normalizeTime(nextKf.frame, timeContext.startFrame, timeContext.endFrame);
1379
1454
  var v0 = getScalarValue(kf, dimensionIndex);
1380
- var v1 = kf.hold === true ? v0 : getScalarValue(nextKf, dimensionIndex);
1455
+ var endKeyframe = kf.endValue != null ? _extends({}, kf, {
1456
+ value: kf.endValue
1457
+ }) : nextKf;
1458
+ var v1 = kf.hold === true ? v0 : getScalarValue(endKeyframe, dimensionIndex);
1381
1459
  var outHandle = kf.hold === true ? {
1382
1460
  x: 0,
1383
1461
  y: 0
@@ -1484,20 +1562,11 @@ function buildPositionTimingCurves(points) {
1484
1562
  }
1485
1563
 
1486
1564
  /**
1487
- * True when the layer's parent only inherits transform — visibility and
1488
- * lifetime are independent of the parent's window.
1489
- *
1490
- * Reads `IRLayerReference.linkKind` directly. Producers that don't set the
1491
- * field (e.g. dsl2ge) effectively get `false` here, which is the correct
1492
- * default for "full" parent containment.
1493
- *
1494
- * Lottie's parser sets `linkKind: 'transform-only'` when a child's parent
1495
- * relationship comes from `layer.parent` rather than precomp expansion;
1496
- * `applyPostProcess` consumes this to decide whether to advance the parent's
1497
- * activation track when the child starts earlier.
1498
- */ function isTransformOnlyParentLink(layer) {
1565
+ * True when the child lifetime is independent of its transform parent's
1566
+ * clipping window. An omitted lifetimeMode keeps the legacy clipped default.
1567
+ */ function hasIndependentParentLifetime(layer) {
1499
1568
  var _layer_parent;
1500
- return ((_layer_parent = layer.parent) == null ? void 0 : _layer_parent.linkKind) === 'transform-only';
1569
+ return ((_layer_parent = layer.parent) == null ? void 0 : _layer_parent.lifetimeMode) === 'independent';
1501
1570
  }
1502
1571
 
1503
1572
  /**
@@ -1505,18 +1574,19 @@ function buildPositionTimingCurves(points) {
1505
1574
  * the time-stretch and offset semantics from `IRTimeContext`.
1506
1575
  *
1507
1576
  * dsl-source IRs leave `stretch` and `offsetFrame` undefined, in which case
1508
- * this collapses to `delay = startFrame / fr` and
1577
+ * this collapses to `delay = (startFrame - compositionInPoint) / fr` and
1509
1578
  * `duration = (endFrame - startFrame) / fr` — exactly what dsl2ge used to
1510
1579
  * compute inline.
1511
1580
  *
1512
1581
  * Zero/negative durations are clamped to a 0.0001 epsilon so GE keeps the
1513
1582
  * activation track alive for the (degenerate) layer.
1514
- */ function computeLayerTiming(layer, frameRate) {
1583
+ */ function computeLayerTiming(layer, frameRate, compositionInPoint) {
1584
+ if (compositionInPoint === void 0) compositionInPoint = 0;
1515
1585
  var _time_stretch, _time_offsetFrame;
1516
1586
  var time = layer.time;
1517
1587
  var stretch = (_time_stretch = time.stretch) != null ? _time_stretch : 1;
1518
1588
  var offsetFrame = (_time_offsetFrame = time.offsetFrame) != null ? _time_offsetFrame : 0;
1519
- var delay = roundNumber((offsetFrame + time.startFrame * stretch) / frameRate, 4);
1589
+ var delay = roundNumber((offsetFrame + time.startFrame * stretch - compositionInPoint) / frameRate, 4);
1520
1590
  var rawDuration = (time.endFrame - time.startFrame) * stretch / frameRate;
1521
1591
  var layerDuration = rawDuration > 0 ? roundNumber(rawDuration, 4) : 0.0001;
1522
1592
  return {
@@ -1528,37 +1598,29 @@ function buildPositionTimingCurves(points) {
1528
1598
  function computeStaticPosition(layer, ctx, anchorOffsetX, anchorOffsetY) {
1529
1599
  if (anchorOffsetX === void 0) anchorOffsetX = 0;
1530
1600
  if (anchorOffsetY === void 0) anchorOffsetY = 0;
1531
- var _transform_position;
1601
+ var _transform_position, _transform_position1, _transform_position_keyframes_, _transform_position2;
1532
1602
  var transform = layer.transform;
1533
- if (transform == null ? void 0 : (_transform_position = transform.position) == null ? void 0 : _transform_position.keyframed) {
1603
+ if ((transform == null ? void 0 : (_transform_position = transform.position) == null ? void 0 : _transform_position.keyframed) === true && transform.position.keyframes.length !== 1) {
1534
1604
  return convert2dTo3dPoint(ctx.width / 2 + anchorOffsetX, ctx.height / 2 + anchorOffsetY, 0, ctx.width, ctx.height);
1535
1605
  }
1536
1606
  var isNullType = layer.type === 'null' || layer.type === 'precomp';
1537
- if ((transform == null ? void 0 : transform.position) != null && Array.isArray(transform.position.value)) {
1607
+ var positionValue = (transform == null ? void 0 : (_transform_position1 = transform.position) == null ? void 0 : _transform_position1.keyframed) === true ? (_transform_position_keyframes_ = transform.position.keyframes[0]) == null ? void 0 : _transform_position_keyframes_.value : transform == null ? void 0 : (_transform_position2 = transform.position) == null ? void 0 : _transform_position2.value;
1608
+ if (Array.isArray(positionValue)) {
1538
1609
  var _pos_, _pos_1, _pos_2;
1539
- var pos = transform.position.value;
1610
+ var pos = positionValue;
1540
1611
  return convert2dTo3dPoint(((_pos_ = pos[0]) != null ? _pos_ : 0) + anchorOffsetX, ((_pos_1 = pos[1]) != null ? _pos_1 : 0) + anchorOffsetY, isNullType ? 0 : (_pos_2 = pos[2]) != null ? _pos_2 : 0, ctx.width, ctx.height);
1541
1612
  }
1542
1613
  return convert2dTo3dPoint(ctx.width / 2 + anchorOffsetX, ctx.height / 2 + anchorOffsetY, 0, ctx.width, ctx.height);
1543
1614
  }
1544
1615
  function getStaticAnchor(layer) {
1545
- var _layer_transform;
1546
- var anchor = (_layer_transform = layer.transform) == null ? void 0 : _layer_transform.anchor;
1547
- if (anchor != null && !anchor.keyframed && Array.isArray(anchor.value) && anchor.value.length >= 2) {
1616
+ var _layer_transform_anchor, _layer_transform;
1617
+ var value = (_layer_transform = layer.transform) == null ? void 0 : (_layer_transform_anchor = _layer_transform.anchor) == null ? void 0 : _layer_transform_anchor.value;
1618
+ if (Array.isArray(value) && value.length >= 2) {
1548
1619
  return [
1549
- anchor.value[0],
1550
- anchor.value[1]
1620
+ value[0],
1621
+ value[1]
1551
1622
  ];
1552
1623
  }
1553
- if ((anchor == null ? void 0 : anchor.keyframed) && anchor.keyframes != null && anchor.keyframes.length > 0) {
1554
- var firstVal = anchor.keyframes[0].value;
1555
- if (Array.isArray(firstVal) && firstVal.length >= 2) {
1556
- return [
1557
- firstVal[0],
1558
- firstVal[1]
1559
- ];
1560
- }
1561
- }
1562
1624
  return [
1563
1625
  0,
1564
1626
  0
@@ -1566,15 +1628,21 @@ function getStaticAnchor(layer) {
1566
1628
  }
1567
1629
  function getStaticScaleFromIR(layer) {
1568
1630
  var _value_, _value_1;
1569
- var _layer_transform;
1631
+ var _layer_transform, _scale_keyframes_;
1570
1632
  var scale = (_layer_transform = layer.transform) == null ? void 0 : _layer_transform.scale;
1571
- if (scale == null || scale.keyframed) {
1633
+ if (scale == null) {
1634
+ return [
1635
+ 1,
1636
+ 1
1637
+ ];
1638
+ }
1639
+ if (scale.keyframed && scale.keyframes.length !== 1) {
1572
1640
  return [
1573
1641
  1,
1574
1642
  1
1575
1643
  ];
1576
1644
  }
1577
- var value = scale.value;
1645
+ var value = scale.keyframed ? (_scale_keyframes_ = scale.keyframes[0]) == null ? void 0 : _scale_keyframes_.value : scale.value;
1578
1646
  if (!Array.isArray(value)) {
1579
1647
  return [
1580
1648
  1,
@@ -1586,14 +1654,15 @@ function getStaticScaleFromIR(layer) {
1586
1654
  (_value_1 = value[1]) != null ? _value_1 : 1
1587
1655
  ];
1588
1656
  }
1589
- function applyScalePositionAdjust(position, layer, layerWidth, layerHeight, ratio) {
1657
+ function applyScalePositionAdjust(position, layer, bounds, ratio) {
1590
1658
  var staticScale = getStaticScaleFromIR(layer);
1591
- if (staticScale[0] === 1 && staticScale[1] === 1 || layerWidth <= 0 || layerHeight <= 0) {
1659
+ var x = bounds.x, y = bounds.y, width = bounds.width, height = bounds.height;
1660
+ if (staticScale[0] === 1 && staticScale[1] === 1 || width <= 0 || height <= 0) {
1592
1661
  return position;
1593
1662
  }
1594
1663
  var anchor = getStaticAnchor(layer);
1595
- var anchorDiffX = anchor[0] - layerWidth / 2;
1596
- var anchorDiffY = anchor[1] - layerHeight / 2;
1664
+ var anchorDiffX = anchor[0] - (x + width / 2);
1665
+ var anchorDiffY = anchor[1] - (y + height / 2);
1597
1666
  if (Math.abs(anchorDiffX) <= 0.5 && Math.abs(anchorDiffY) <= 0.5) {
1598
1667
  return position;
1599
1668
  }
@@ -1603,43 +1672,46 @@ function applyScalePositionAdjust(position, layer, layerWidth, layerHeight, rati
1603
1672
  position[2]
1604
1673
  ];
1605
1674
  }
1606
- function computeAnchorInfo(layer, layerWidth, layerHeight) {
1675
+ function computeAnchorInfo(layer, bounds) {
1607
1676
  var anchor = getStaticAnchor(layer);
1677
+ var x = bounds.x, y = bounds.y, width = bounds.width, height = bounds.height;
1678
+ var localAnchorX = anchor[0] - x;
1679
+ var localAnchorY = anchor[1] - y;
1608
1680
  var anchorScaleX = 0.5;
1609
1681
  var anchorScaleY = 0.5;
1610
1682
  var anchorOffsetX = 0;
1611
1683
  var anchorOffsetY = 0;
1612
- if (layerWidth > 0 && layerHeight > 0) {
1613
- anchorScaleX = anchor[0] / layerWidth;
1614
- anchorScaleY = anchor[1] / layerHeight;
1615
- anchorOffsetX = -(anchor[0] - layerWidth / 2);
1616
- anchorOffsetY = -(anchor[1] - layerHeight / 2);
1684
+ if (width > 0 && height > 0) {
1685
+ anchorScaleX = localAnchorX / width;
1686
+ anchorScaleY = localAnchorY / height;
1687
+ anchorOffsetX = -(localAnchorX - width / 2);
1688
+ anchorOffsetY = -(localAnchorY - height / 2);
1617
1689
  }
1618
- if (layer.type === 'text' && layer.text != null && layerWidth > 0 && layerHeight > 0) {
1690
+ if (layer.type === 'text' && layer.text != null && width > 0 && height > 0) {
1619
1691
  if (layer.text.anchorAdjust === true) {
1620
1692
  if (layer.text.textAlign === 'left') {
1621
- anchorOffsetX = -(anchor[0] - layerWidth / 2);
1622
- anchorScaleX = anchor[0] / layerWidth - 0.5;
1693
+ anchorOffsetX = -(localAnchorX - width / 2);
1694
+ anchorScaleX = localAnchorX / width - 0.5;
1623
1695
  }
1624
1696
  if (layer.text.textAlign === 'center') {
1625
- anchorOffsetX = -anchor[0];
1626
- anchorScaleX = anchor[0] / layerWidth + 0.5;
1697
+ anchorOffsetX = -localAnchorX;
1698
+ anchorScaleX = localAnchorX / width + 0.5;
1627
1699
  }
1628
1700
  if (layer.text.textAlign === 'right') {
1629
- anchorOffsetX = -(anchor[0] + layerWidth / 2);
1630
- anchorScaleX = anchor[0] / layerWidth + 1.5;
1701
+ anchorOffsetX = -(localAnchorX + width / 2);
1702
+ anchorScaleX = localAnchorX / width + 1.5;
1631
1703
  }
1632
1704
  // GE renders glyphs in the lower half of the quad, so offset by half the
1633
1705
  // layer height to align the visible text center with Lottie's anchor.
1634
- var textHeight = layerHeight / 2;
1635
- anchorOffsetY = -(anchor[1] + textHeight);
1636
- anchorScaleY = -anchor[1] / textHeight;
1706
+ var textHeight = height / 2;
1707
+ anchorOffsetY = -(localAnchorY + textHeight);
1708
+ anchorScaleY = -localAnchorY / textHeight;
1637
1709
  }
1638
1710
  }
1639
1711
  var isSpriteForAnchor = layer.type === 'image' || layer.type === 'solid';
1640
1712
  var staticRotationZ = getStaticRotationZ(layer);
1641
1713
  var hasStaticRotation = staticRotationZ != null;
1642
- if (isSpriteForAnchor && hasStaticRotation && isTransformOnlyParentLink(layer) && (anchorOffsetX !== 0 || anchorOffsetY !== 0)) {
1714
+ if (isSpriteForAnchor && hasStaticRotation && hasIndependentParentLifetime(layer) && (anchorOffsetX !== 0 || anchorOffsetY !== 0)) {
1643
1715
  var rotValue = staticRotationZ != null ? staticRotationZ : 0;
1644
1716
  if (rotValue !== 0) {
1645
1717
  var rad = rotValue * Math.PI / 180;
@@ -1659,15 +1731,10 @@ function computeAnchorInfo(layer, layerWidth, layerHeight) {
1659
1731
  };
1660
1732
  }
1661
1733
  function getStaticRotationZ(layer) {
1662
- var _layer_transform, _layer_transform_separatedRotation, _layer_transform1;
1663
- var rotation = (_layer_transform = layer.transform) == null ? void 0 : _layer_transform.rotation;
1664
- if (rotation != null && !rotation.keyframed && Array.isArray(rotation.value)) {
1665
- var _rotation_value_;
1666
- return (_rotation_value_ = rotation.value[2]) != null ? _rotation_value_ : 0;
1667
- }
1668
- var separatedRotationZ = (_layer_transform1 = layer.transform) == null ? void 0 : (_layer_transform_separatedRotation = _layer_transform1.separatedRotation) == null ? void 0 : _layer_transform_separatedRotation.z;
1669
- if (separatedRotationZ != null && !separatedRotationZ.keyframed && typeof separatedRotationZ.value === 'number') {
1670
- return separatedRotationZ.value;
1734
+ var _layer_transform_rotation, _layer_transform;
1735
+ var rotationZ = (_layer_transform = layer.transform) == null ? void 0 : (_layer_transform_rotation = _layer_transform.rotation) == null ? void 0 : _layer_transform_rotation.z;
1736
+ if (rotationZ != null && !rotationZ.keyframed && typeof rotationZ.value === 'number') {
1737
+ return rotationZ.value;
1671
1738
  }
1672
1739
  return undefined;
1673
1740
  }
@@ -1678,99 +1745,50 @@ function getTimeContext(layer) {
1678
1745
  };
1679
1746
  }
1680
1747
 
1681
- function readGE2IRMetadata(ir, layer) {
1682
- if (ir.source !== 'ge') {
1683
- return undefined;
1684
- }
1685
- var metadata = layer.metadata;
1686
- if (metadata == null) {
1687
- return undefined;
1688
- }
1689
- var namespaced = metadata['ge2ir'];
1690
- if (isRecord$4(namespaced)) {
1691
- return namespaced;
1692
- }
1693
- var legacy = readLegacyGE2IRMetadata(metadata);
1694
- return Object.keys(legacy).length > 0 ? legacy : undefined;
1695
- }
1696
- function readLegacyGE2IRMetadata(metadata) {
1697
- var legacy = {};
1698
- var positionOverLifetime = metadata['positionOverLifetime'];
1699
- var rotationOverLifetime = metadata['rotationOverLifetime'];
1700
- var sizeOverLifetime = metadata['sizeOverLifetime'];
1701
- var colorOverLifetime = metadata['colorOverLifetime'];
1702
- var geComponentId = metadata['geComponentId'];
1703
- var geMask = metadata['geMask'];
1704
- var precompRefId = metadata['precompRefId'];
1705
- var precompContent = metadata['precompContent'];
1706
- if (isRecord$4(positionOverLifetime)) {
1707
- legacy.positionOverLifetime = positionOverLifetime;
1708
- }
1709
- if (isRecord$4(rotationOverLifetime)) {
1710
- legacy.rotationOverLifetime = rotationOverLifetime;
1711
- }
1712
- if (isRecord$4(sizeOverLifetime)) {
1713
- legacy.sizeOverLifetime = sizeOverLifetime;
1714
- }
1715
- if (isRecord$4(colorOverLifetime)) {
1716
- legacy.colorOverLifetime = colorOverLifetime;
1717
- }
1718
- if (typeof geComponentId === 'string') {
1719
- legacy.geComponentId = geComponentId;
1720
- }
1721
- if (isRecord$4(geMask)) {
1722
- legacy.geMask = geMask;
1723
- }
1724
- if (typeof precompRefId === 'string') {
1725
- legacy.precompRefId = precompRefId;
1726
- }
1727
- if (isRecord$4(precompContent)) {
1728
- legacy.precompContent = precompContent;
1729
- }
1730
- return legacy;
1731
- }
1732
- function readGE2IRCompositionMetadata(ir) {
1733
- if (ir.source !== 'ge') {
1734
- return undefined;
1735
- }
1736
- var metadata = ir.metadata;
1737
- if (metadata == null) {
1738
- return undefined;
1739
- }
1740
- var namespaced = metadata['ge2ir'];
1741
- return isRecord$4(namespaced) ? namespaced : undefined;
1742
- }
1743
- function isRecord$4(value) {
1744
- return value != null && (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object' && !Array.isArray(value);
1745
- }
1746
-
1747
1748
  function buildTransformAnimation(layer, ctx) {
1748
- var transform = layer.transform;
1749
- if (transform == null) {
1749
+ if (layer.transform == null) {
1750
1750
  return {};
1751
1751
  }
1752
- var timeContext = getTimeContext(layer);
1753
- // Passthrough: ge2ir stores raw animation data in metadata to bypass the
1752
+ // Passthrough: ge2ir stores raw animation data in specific.effects to bypass the
1754
1753
  // IR keyframe conversion pipeline. Raw GE data is used verbatim when
1755
1754
  // available; otherwise the standard IR → GE conversion runs.
1756
- var ge2irMetadata = readGE2IRMetadata(ctx.ir, layer);
1757
- var passthroughPosition = ge2irMetadata == null ? void 0 : ge2irMetadata.positionOverLifetime;
1758
- var passthroughRotation = ge2irMetadata == null ? void 0 : ge2irMetadata.rotationOverLifetime;
1759
- var passthroughSize = ge2irMetadata == null ? void 0 : ge2irMetadata.sizeOverLifetime;
1760
- var positionOverLifetime = passthroughPosition != null ? passthroughPosition : buildPositionAnim(transform, timeContext, ctx);
1761
- var rotationOverLifetime = passthroughRotation != null ? passthroughRotation : buildRotationAnim(transform, timeContext);
1762
- var sizeOverLifetime = passthroughSize != null ? passthroughSize : buildSizeAnim(transform, timeContext);
1755
+ var effectsSpecific = getEffectsLayerSpecific(ctx.ir, layer);
1756
+ var passthroughPosition = effectsSpecific == null ? void 0 : effectsSpecific.positionOverLifetime;
1757
+ var passthroughRotation = effectsSpecific == null ? void 0 : effectsSpecific.rotationOverLifetime;
1758
+ var passthroughSize = effectsSpecific == null ? void 0 : effectsSpecific.sizeOverLifetime;
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;
1763
1763
  return {
1764
1764
  positionOverLifetime: positionOverLifetime,
1765
1765
  rotationOverLifetime: rotationOverLifetime,
1766
1766
  sizeOverLifetime: sizeOverLifetime
1767
1767
  };
1768
1768
  }
1769
- function buildPositionAnim(transform, timeContext, ctx) {
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
+ }
1785
+ function buildPositionAnim(layer, transform, timeContext, ctx) {
1770
1786
  var _posResult_curves_;
1787
+ var _posResult_pathPoints_;
1771
1788
  if (transform.position == null || !transform.position.keyframed) {
1772
1789
  return undefined;
1773
1790
  }
1791
+ assertContiguousPositionSegments(transform.position, layer);
1774
1792
  var posResult = irPositionKeyframesToGE(transform.position, timeContext);
1775
1793
  if (posResult == null) {
1776
1794
  return undefined;
@@ -1778,28 +1796,28 @@ function buildPositionAnim(transform, timeContext, ctx) {
1778
1796
  var pathPoints = [];
1779
1797
  var controlPoints = [];
1780
1798
  var useKeyframeMode = shouldUseKeyframeMode(transform.position);
1781
- for(var _iterator = _create_for_of_iterator_helper_loose(posResult.pathPoints), _step; !(_step = _iterator()).done;){
1782
- var pp = _step.value;
1783
- var point3d = convert2dTo3dPoint(pp[0][0], pp[0][1], 0, ctx.width, ctx.height);
1799
+ var firstPathPoint = (_posResult_pathPoints_ = posResult.pathPoints[0]) == null ? void 0 : _posResult_pathPoints_[0];
1800
+ if (firstPathPoint != null) {
1801
+ var point3d = convert2dTo3dPoint(firstPathPoint[0], firstPathPoint[1], 0, ctx.width, ctx.height);
1784
1802
  pathPoints.push(point3d);
1785
1803
  }
1786
- if (posResult.pathPoints.length > 0) {
1787
- var lastPp = posResult.pathPoints[posResult.pathPoints.length - 1];
1788
- var lastPoint3d = convert2dTo3dPoint(lastPp[1][0], lastPp[1][1], 0, ctx.width, ctx.height);
1789
- pathPoints.push(lastPoint3d);
1804
+ for(var _iterator = _create_for_of_iterator_helper_loose(posResult.pathPoints), _step; !(_step = _iterator()).done;){
1805
+ var pathPoint = _step.value;
1806
+ var endPoint3d = convert2dTo3dPoint(pathPoint[1][0], pathPoint[1][1], 0, ctx.width, ctx.height);
1807
+ pathPoints.push(endPoint3d);
1790
1808
  }
1791
1809
  for(var i = 0; i < posResult.controlPoints.length; i++){
1792
1810
  var cp = posResult.controlPoints[i];
1793
- var pp1 = posResult.pathPoints[i];
1811
+ var pp = posResult.pathPoints[i];
1794
1812
  if (useKeyframeMode) {
1795
- var dx = pp1[1][0] - pp1[0][0];
1796
- var dy = pp1[1][1] - pp1[0][1];
1797
- var cp1 = convert2dTo3dPoint(dx / 3 + pp1[0][0], dy / 3 + pp1[0][1], 0, ctx.width, ctx.height);
1798
- var cp2 = convert2dTo3dPoint(-dx / 3 + pp1[1][0], -dy / 3 + pp1[1][1], 0, ctx.width, ctx.height);
1813
+ var dx = pp[1][0] - pp[0][0];
1814
+ var dy = pp[1][1] - pp[0][1];
1815
+ var cp1 = convert2dTo3dPoint(dx / 3 + pp[0][0], dy / 3 + pp[0][1], 0, ctx.width, ctx.height);
1816
+ var cp2 = convert2dTo3dPoint(-dx / 3 + pp[1][0], -dy / 3 + pp[1][1], 0, ctx.width, ctx.height);
1799
1817
  controlPoints.push(cp1, cp2);
1800
1818
  } else {
1801
- var cp11 = convert2dTo3dPoint(cp[0][0] + pp1[0][0], cp[0][1] + pp1[0][1], 0, ctx.width, ctx.height);
1802
- var cp21 = convert2dTo3dPoint(cp[1][0] + pp1[1][0], cp[1][1] + pp1[1][1], 0, ctx.width, ctx.height);
1819
+ var cp11 = convert2dTo3dPoint(cp[0][0] + pp[0][0], cp[0][1] + pp[0][1], 0, ctx.width, ctx.height);
1820
+ var cp21 = convert2dTo3dPoint(cp[1][0] + pp[1][0], cp[1][1] + pp[1][1], 0, ctx.width, ctx.height);
1803
1821
  controlPoints.push(cp11, cp21);
1804
1822
  }
1805
1823
  }
@@ -1838,112 +1856,39 @@ function buildPositionAnim(transform, timeContext, ctx) {
1838
1856
  ]
1839
1857
  };
1840
1858
  }
1859
+ function assertContiguousPositionSegments(position, layer) {
1860
+ var _loop = function(index) {
1861
+ var segmentEnd = position.keyframes[index].endValue;
1862
+ var nextStart = position.keyframes[index + 1].value;
1863
+ if (segmentEnd == null) {
1864
+ return "continue";
1865
+ }
1866
+ var isContiguous = segmentEnd.every(function(value, dimension) {
1867
+ return Math.abs(value - nextStart[dimension]) <= 1e-6;
1868
+ });
1869
+ if (!isContiguous) {
1870
+ throw new Error("[ge-ir] Layer '" + layer.name + "' has a discontiguous position segment at keyframe " + index + "; " + 'GE path animation cannot preserve a segment endValue that differs from the next keyframe value.');
1871
+ }
1872
+ };
1873
+ for(var index = 0; index < position.keyframes.length - 1; index++)_loop(index);
1874
+ }
1841
1875
  function buildRotationAnim(transform, timeContext) {
1842
1876
  var result = {};
1843
- var hasZ = false;
1844
- var hasX = false;
1845
- var hasY = false;
1846
1877
  var rotation = transform.rotation;
1847
- if (rotation != null) {
1848
- if (rotation.keyframed) {
1849
- var _curves_, _curves_1, _curves_2;
1850
- var curves = irVectorKeyframesToGE(rotation, timeContext);
1851
- if (curves != null && axisHasRotationValue(rotation, 0) && ((_curves_ = curves[0]) == null ? void 0 : _curves_.length)) {
1852
- result['x'] = [
1853
- ValueType.BEZIER_CURVE,
1854
- curves[0]
1855
- ];
1856
- hasX = true;
1857
- }
1858
- if (curves != null && axisHasRotationValue(rotation, 1) && ((_curves_1 = curves[1]) == null ? void 0 : _curves_1.length)) {
1859
- result['y'] = [
1860
- ValueType.BEZIER_CURVE,
1861
- curves[1]
1862
- ];
1863
- hasY = true;
1864
- }
1865
- if (curves != null && axisHasRotationValue(rotation, 2) && ((_curves_2 = curves[2]) == null ? void 0 : _curves_2.length)) {
1866
- result['z'] = [
1867
- ValueType.BEZIER_CURVE,
1868
- curves[2]
1869
- ];
1870
- hasZ = true;
1871
- }
1872
- } else if (rotation.value != null) {
1873
- var _rotation_value = rotation.value, tmp = _rotation_value[0], x = tmp === void 0 ? 0 : tmp, tmp1 = _rotation_value[1], y = tmp1 === void 0 ? 0 : tmp1, tmp2 = _rotation_value[2], z = tmp2 === void 0 ? 0 : tmp2;
1874
- if (Math.abs(x) > 0.0001) {
1875
- result['x'] = [
1876
- ValueType.CONSTANT,
1877
- x
1878
- ];
1879
- hasX = true;
1880
- }
1881
- if (Math.abs(y) > 0.0001) {
1882
- result['y'] = [
1883
- ValueType.CONSTANT,
1884
- y
1885
- ];
1886
- hasY = true;
1887
- }
1888
- if (Math.abs(z) > 0.0001) {
1889
- result['z'] = [
1890
- ValueType.CONSTANT,
1891
- z
1892
- ];
1893
- hasZ = true;
1894
- }
1895
- }
1896
- } else {
1897
- var _separated_x, _separated_x1, _separated_y, _separated_y1, _separated_z, _separated_z1;
1898
- var separated = transform.separatedRotation;
1899
- if (separated == null ? void 0 : (_separated_x = separated.x) == null ? void 0 : _separated_x.keyframed) {
1900
- var curves1 = irScalarKeyframesToGE(separated.x, timeContext);
1901
- if (curves1 != null) {
1902
- result['x'] = [
1903
- ValueType.BEZIER_CURVE,
1904
- curves1[0]
1905
- ];
1906
- hasX = true;
1907
- }
1908
- } else if ((separated == null ? void 0 : (_separated_x1 = separated.x) == null ? void 0 : _separated_x1.value) != null && separated.x.value !== 0) {
1909
- result['x'] = [
1910
- ValueType.CONSTANT,
1911
- separated.x.value
1912
- ];
1913
- hasX = true;
1914
- }
1915
- if (separated == null ? void 0 : (_separated_y = separated.y) == null ? void 0 : _separated_y.keyframed) {
1916
- var curves2 = irScalarKeyframesToGE(separated.y, timeContext);
1917
- if (curves2 != null) {
1918
- result['y'] = [
1919
- ValueType.BEZIER_CURVE,
1920
- curves2[0]
1921
- ];
1922
- hasY = true;
1923
- }
1924
- } else if ((separated == null ? void 0 : (_separated_y1 = separated.y) == null ? void 0 : _separated_y1.value) != null && separated.y.value !== 0) {
1925
- result['y'] = [
1926
- ValueType.CONSTANT,
1927
- separated.y.value
1928
- ];
1929
- hasY = true;
1930
- }
1931
- if (separated == null ? void 0 : (_separated_z = separated.z) == null ? void 0 : _separated_z.keyframed) {
1932
- var curves3 = irScalarKeyframesToGE(separated.z, timeContext);
1933
- if (curves3 != null) {
1934
- result['z'] = [
1935
- ValueType.BEZIER_CURVE,
1936
- curves3[0]
1937
- ];
1938
- hasZ = true;
1939
- }
1940
- } else if ((separated == null ? void 0 : (_separated_z1 = separated.z) == null ? void 0 : _separated_z1.value) != null && separated.z.value !== 0) {
1941
- result['z'] = [
1942
- ValueType.CONSTANT,
1943
- separated.z.value
1944
- ];
1945
- hasZ = true;
1946
- }
1878
+ var x = buildRotationAxis(rotation == null ? void 0 : rotation.x, timeContext);
1879
+ var y = buildRotationAxis(rotation == null ? void 0 : rotation.y, timeContext);
1880
+ var z = buildRotationAxis(rotation == null ? void 0 : rotation.z, timeContext);
1881
+ var hasX = x != null;
1882
+ var hasY = y != null;
1883
+ var hasZ = z != null;
1884
+ if (x != null) {
1885
+ result['x'] = x;
1886
+ }
1887
+ if (y != null) {
1888
+ result['y'] = y;
1889
+ }
1890
+ if (z != null) {
1891
+ result['z'] = z;
1947
1892
  }
1948
1893
  if (!hasZ && !hasX && !hasY) {
1949
1894
  return undefined;
@@ -1955,25 +1900,46 @@ function buildRotationAnim(transform, timeContext) {
1955
1900
  }
1956
1901
  return result;
1957
1902
  }
1958
- function axisHasRotationValue(rotation, axis) {
1959
- var _ref;
1960
- var _rotation_keyframes;
1961
- if (!rotation.keyframed) {
1962
- var _ref1;
1963
- var _rotation_value;
1964
- return Math.abs((_ref1 = (_rotation_value = rotation.value) == null ? void 0 : _rotation_value[axis]) != null ? _ref1 : 0) > 0.0001;
1903
+ function buildRotationAxis(property, timeContext) {
1904
+ if (property == null) {
1905
+ return undefined;
1965
1906
  }
1966
- return (_ref = (_rotation_keyframes = rotation.keyframes) == null ? void 0 : _rotation_keyframes.some(function(keyframe) {
1967
- var _keyframe_value_axis, _ref;
1907
+ if (!property.keyframed) {
1908
+ return property.value !== 0 ? [
1909
+ ValueType.CONSTANT,
1910
+ property.value
1911
+ ] : undefined;
1912
+ }
1913
+ if (property.keyframes.length === 1) {
1914
+ var value = property.keyframes[0].value;
1915
+ return value !== 0 ? [
1916
+ ValueType.CONSTANT,
1917
+ value
1918
+ ] : undefined;
1919
+ }
1920
+ if (!axisHasRotationValue(property)) {
1921
+ return undefined;
1922
+ }
1923
+ var curves = irScalarKeyframesToGE(property, timeContext);
1924
+ return curves != null ? [
1925
+ ValueType.BEZIER_CURVE,
1926
+ curves[0]
1927
+ ] : undefined;
1928
+ }
1929
+ function axisHasRotationValue(rotation) {
1930
+ return rotation.keyframes.some(function(keyframe) {
1968
1931
  var _keyframe_endValue;
1969
- return Math.abs((_keyframe_value_axis = keyframe.value[axis]) != null ? _keyframe_value_axis : 0) > 0.0001 || Math.abs((_ref = (_keyframe_endValue = keyframe.endValue) == null ? void 0 : _keyframe_endValue[axis]) != null ? _ref : 0) > 0.0001;
1970
- })) != null ? _ref : false;
1932
+ return Math.abs(keyframe.value) > 0.0001 || Math.abs((_keyframe_endValue = keyframe.endValue) != null ? _keyframe_endValue : 0) > 0.0001;
1933
+ });
1971
1934
  }
1972
1935
  function buildSizeAnim(transform, timeContext) {
1973
1936
  if (transform.scale == null) {
1974
1937
  return undefined;
1975
1938
  }
1976
1939
  if (transform.scale.keyframed) {
1940
+ if (transform.scale.keyframes.length === 1) {
1941
+ return buildConstantSizeAnimation(transform.scale.keyframes[0].value);
1942
+ }
1977
1943
  var curves = irVectorKeyframesToGE(transform.scale, timeContext);
1978
1944
  if (curves != null && curves.length >= 2) {
1979
1945
  return _extends({
@@ -1995,33 +1961,37 @@ function buildSizeAnim(transform, timeContext) {
1995
1961
  }
1996
1962
  return undefined;
1997
1963
  }
1998
- var scale = transform.scale.value;
1999
- if (Array.isArray(scale) && (Math.abs(scale[0] - 1) > 0.0001 || Math.abs(scale[1] - 1) > 0.0001)) {
2000
- var _scale_;
2001
- return {
2002
- separateAxes: true,
2003
- x: [
2004
- ValueType.CONSTANT,
2005
- scale[0]
2006
- ],
2007
- y: [
2008
- ValueType.CONSTANT,
2009
- scale[1]
2010
- ],
2011
- z: [
2012
- ValueType.CONSTANT,
2013
- (_scale_ = scale[2]) != null ? _scale_ : 1
2014
- ]
2015
- };
1964
+ return buildConstantSizeAnimation(transform.scale.value);
1965
+ }
1966
+ function buildConstantSizeAnimation(scale) {
1967
+ if (Math.abs(scale[0] - 1) <= 0.0001 && Math.abs(scale[1] - 1) <= 0.0001) {
1968
+ return undefined;
2016
1969
  }
2017
- return undefined;
1970
+ return {
1971
+ separateAxes: true,
1972
+ x: [
1973
+ ValueType.CONSTANT,
1974
+ scale[0]
1975
+ ],
1976
+ y: [
1977
+ ValueType.CONSTANT,
1978
+ scale[1]
1979
+ ],
1980
+ z: [
1981
+ ValueType.CONSTANT,
1982
+ scale[2]
1983
+ ]
1984
+ };
2018
1985
  }
2019
1986
  function buildColorAnimation(layer, ir) {
2020
- var _readGE2IRMetadata;
2021
- var passthroughColor = (_readGE2IRMetadata = readGE2IRMetadata(ir, layer)) == null ? void 0 : _readGE2IRMetadata.colorOverLifetime;
1987
+ var _getEffectsLayerSpecific;
1988
+ var passthroughColor = (_getEffectsLayerSpecific = getEffectsLayerSpecific(ir, layer)) == null ? void 0 : _getEffectsLayerSpecific.colorOverLifetime;
2022
1989
  if (passthroughColor != null) {
2023
1990
  return passthroughColor;
2024
1991
  }
1992
+ return buildNormalizedColorAnimation(layer);
1993
+ }
1994
+ /** Encode normalized IR opacity as a GE color-over-lifetime payload. */ function buildNormalizedColorAnimation(layer) {
2025
1995
  var transform = layer.transform;
2026
1996
  if ((transform == null ? void 0 : transform.opacity) == null) {
2027
1997
  return undefined;
@@ -2036,6 +2006,15 @@ function buildColorAnimation(layer, ir) {
2036
2006
  };
2037
2007
  }
2038
2008
  if (transform.opacity.keyframed) {
2009
+ if (transform.opacity.keyframes.length === 1) {
2010
+ var opacityValue = transform.opacity.keyframes[0].value;
2011
+ return opacityValue !== 1 ? {
2012
+ opacity: [
2013
+ ValueType.CONSTANT,
2014
+ opacityValue
2015
+ ]
2016
+ } : undefined;
2017
+ }
2039
2018
  var curves = irScalarKeyframesToGE(transform.opacity, timeContext);
2040
2019
  if (curves != null) {
2041
2020
  return {
@@ -2047,12 +2026,12 @@ function buildColorAnimation(layer, ir) {
2047
2026
  }
2048
2027
  return undefined;
2049
2028
  }
2050
- var opacityValue = transform.opacity.value;
2051
- if (typeof opacityValue === 'number' && opacityValue !== 1) {
2029
+ var opacityValue1 = transform.opacity.value;
2030
+ if (typeof opacityValue1 === 'number' && opacityValue1 !== 1) {
2052
2031
  return {
2053
2032
  opacity: [
2054
2033
  ValueType.CONSTANT,
2055
- opacityValue
2034
+ opacityValue1
2056
2035
  ]
2057
2036
  };
2058
2037
  }
@@ -2134,18 +2113,20 @@ function mapBlendingMode(blendMode) {
2134
2113
  return GE_BLENDING_BY_IR_MODE[blendMode];
2135
2114
  }
2136
2115
 
2137
- var DEFAULT_DISPLAY_SIZE = {
2116
+ var DEFAULT_LOCAL_BOUNDS = {
2117
+ x: 0,
2118
+ y: 0,
2138
2119
  width: 1,
2139
2120
  height: 1
2140
2121
  };
2141
2122
  /**
2142
- * Read the producer-baked display size from an IR layer. When the producer
2143
- * did not resolve one, returns `fallback` (defaults to `{ 1, 1 }` — the
2144
- * value every existing call site was using inline).
2145
- */ function getLayerDisplaySize(layer, fallback) {
2146
- if (fallback === void 0) fallback = DEFAULT_DISPLAY_SIZE;
2147
- var _layer_displaySize;
2148
- return (_layer_displaySize = layer.displaySize) != null ? _layer_displaySize : fallback;
2123
+ * Read source-neutral local bounds from an IR layer. When the producer
2124
+ * did not resolve one, returns `fallback` (defaults to bounds at the origin
2125
+ * with a one-pixel width and height).
2126
+ */ function getLayerLocalBounds(layer, fallback) {
2127
+ if (fallback === void 0) fallback = DEFAULT_LOCAL_BOUNDS;
2128
+ var _layer_localBounds;
2129
+ return (_layer_localBounds = layer.localBounds) != null ? _layer_localBounds : fallback;
2149
2130
  }
2150
2131
 
2151
2132
  function buildComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
@@ -2162,21 +2143,20 @@ function buildComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
2162
2143
  }
2163
2144
  }
2164
2145
  /**
2165
- * Copy the raw GE mask object (from ge2ir passthrough metadata) onto a freshly
2146
+ * Copy the raw GE mask object (from specific.effects passthrough) onto a freshly
2166
2147
  * built component, as a top-level `mask` field matching GE's structure. For a
2167
2148
  * mask SOURCE this carries `{isMask:true, alphaMaskEnabled}`; for a TARGET it
2168
2149
  * carries `{isMask:false, reference, inverted}` where `reference.id` is still
2169
- * the stale GE1 component id — `applyGeMaskRemap` rewrites it in post-process.
2170
- * No-op for non-ge sources (Lottie masks go through the IRLayerNode.mask path).
2171
- */ function applyGeMask(ir, layer, component) {
2172
- var _readGE2IRMetadata;
2173
- var geMask = (_readGE2IRMetadata = readGE2IRMetadata(ir, layer)) == null ? void 0 : _readGE2IRMetadata.geMask;
2174
- if (geMask != null && component['mask'] == null) {
2175
- component['mask'] = _extends({}, geMask);
2150
+ * the stale GE1 component id — `applyGEMaskRemap` rewrites it in post-process.
2151
+ * No-op for non-GE sources (Lottie masks go through the IRLayerNode.mask path).
2152
+ */ function applyGEMask(ir, layer, component) {
2153
+ var _getEffectsLayerSpecific;
2154
+ var effectsMask = (_getEffectsLayerSpecific = getEffectsLayerSpecific(ir, layer)) == null ? void 0 : _getEffectsLayerSpecific.mask;
2155
+ if (effectsMask != null && component['mask'] == null) {
2156
+ component['mask'] = _extends({}, effectsMask);
2176
2157
  }
2177
2158
  }
2178
2159
  function buildSpriteComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
2179
- var _ref;
2180
2160
  var _layer_asset, _layer_asset1;
2181
2161
  var componentId = createId();
2182
2162
  var blending = mapBlendingMode(layer.blendMode);
@@ -2192,7 +2172,8 @@ function buildSpriteComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
2192
2172
  1
2193
2173
  ];
2194
2174
  var textureDataPath;
2195
- var textureUrl = (_ref = (_layer_asset = layer.asset) == null ? void 0 : _layer_asset.url) != null ? _ref : (_layer_asset1 = layer.asset) == null ? void 0 : _layer_asset1.refId;
2175
+ var assetUrl = (_layer_asset = layer.asset) == null ? void 0 : _layer_asset.url;
2176
+ var textureUrl = assetUrl != null && assetUrl !== '' ? assetUrl : (_layer_asset1 = layer.asset) == null ? void 0 : _layer_asset1.refId;
2196
2177
  if (textureUrl != null && textureUrl !== '' && textureUrl !== 'mask://placeholder') {
2197
2178
  textureDataPath = registerTexture(ctx.collector, textureUrl, ctx.textureCache);
2198
2179
  }
@@ -2218,7 +2199,7 @@ function buildSpriteComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
2218
2199
  roundNumber(anchorScaleY, 4)
2219
2200
  ];
2220
2201
  }
2221
- applyGeMask(ctx.ir, layer, component);
2202
+ applyGEMask(ctx.ir, layer, component);
2222
2203
  ctx.collector.components.push(component);
2223
2204
  return componentId;
2224
2205
  }
@@ -2239,7 +2220,7 @@ function buildTextComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
2239
2220
  var textWidth = (_textInfo_width = textInfo.width) != null ? _textInfo_width : estimateTextWidth(textInfo.content, textInfo.fontSize, textInfo.letterSpacing);
2240
2221
  var lineHeight = typeof textInfo.lineHeight === 'number' && textInfo.lineHeight > 0 ? textInfo.lineHeight : textInfo.fontSize;
2241
2222
  var textHeight = Math.max((_textInfo_height = textInfo.height) != null ? _textInfo_height : textInfo.fontSize * 1.2, lineHeight);
2242
- var _getLayerDisplaySize = getLayerDisplaySize(layer), layerWidth = _getLayerDisplaySize.width, layerHeight = _getLayerDisplaySize.height;
2223
+ var _getLayerLocalBounds = getLayerLocalBounds(layer), layerWidth = _getLayerLocalBounds.width, layerHeight = _getLayerLocalBounds.height;
2243
2224
  var textSizeW = roundNumber(ctx.ratio * layerWidth, 4);
2244
2225
  var textSizeH = roundNumber(ctx.ratio * layerHeight, 4);
2245
2226
  var component = {
@@ -2274,7 +2255,7 @@ function buildTextComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx) {
2274
2255
  blending: blending
2275
2256
  })
2276
2257
  };
2277
- applyGeMask(ctx.ir, layer, component);
2258
+ applyGEMask(ctx.ir, layer, component);
2278
2259
  ctx.collector.components.push(component);
2279
2260
  return componentId;
2280
2261
  }
@@ -2296,7 +2277,7 @@ function buildShapeComponent(layer, itemId, ctx) {
2296
2277
  blending: blending
2297
2278
  })
2298
2279
  });
2299
- applyGeMask(ctx.ir, layer, component);
2280
+ applyGEMask(ctx.ir, layer, component);
2300
2281
  ctx.collector.components.push(component);
2301
2282
  return componentId;
2302
2283
  }
@@ -2304,21 +2285,35 @@ function buildShapeOptions(shapeData, ratio, ctx) {
2304
2285
  var options = {
2305
2286
  type: mapShapePrimitiveType(shapeData.primitiveType)
2306
2287
  };
2307
- if (shapeData.size != null) {
2308
- options['xSize'] = roundNumber(shapeData.size[0] * ratio, 4);
2309
- options['ySize'] = roundNumber(shapeData.size[1] * ratio, 4);
2310
- }
2311
- setScaledNumber(options, shapeData, 'xRadius', ratio);
2312
- setScaledNumber(options, shapeData, 'yRadius', ratio);
2313
- setScaledNumber(options, shapeData, 'width', ratio);
2314
- setScaledNumber(options, shapeData, 'height', ratio);
2315
- setScaledNumber(options, shapeData, 'innerRadius', ratio);
2316
- setScaledNumber(options, shapeData, 'outerRadius', ratio);
2317
- setScaledNumber(options, shapeData, 'radius', ratio);
2318
- setRawNumber(options, shapeData, 'roundness');
2319
- setRawNumber(options, shapeData, 'pointCount');
2320
- setRawNumber(options, shapeData, 'innerRoundness');
2321
- setRawNumber(options, shapeData, 'outerRoundness');
2288
+ switch(shapeData.primitiveType){
2289
+ case animationIr.IRShapePrimitiveType.Custom:
2290
+ Object.assign(options, mapCustomPaths(shapeData.customPaths, ratio));
2291
+ break;
2292
+ case animationIr.IRShapePrimitiveType.Rectangle:
2293
+ var _shapeData_roundness;
2294
+ options['width'] = roundNumber(shapeData.width * ratio, 4);
2295
+ options['height'] = roundNumber(shapeData.height * ratio, 4);
2296
+ options['roundness'] = (_shapeData_roundness = shapeData.roundness) != null ? _shapeData_roundness : 0;
2297
+ break;
2298
+ case animationIr.IRShapePrimitiveType.Ellipse:
2299
+ options['xRadius'] = roundNumber(shapeData.xRadius * ratio, 4);
2300
+ options['yRadius'] = roundNumber(shapeData.yRadius * ratio, 4);
2301
+ break;
2302
+ case animationIr.IRShapePrimitiveType.Polygon:
2303
+ var _shapeData_roundness1;
2304
+ options['pointCount'] = shapeData.pointCount;
2305
+ options['radius'] = roundNumber(shapeData.radius * ratio, 4);
2306
+ options['roundness'] = (_shapeData_roundness1 = shapeData.roundness) != null ? _shapeData_roundness1 : 0;
2307
+ break;
2308
+ case animationIr.IRShapePrimitiveType.Star:
2309
+ var _shapeData_innerRoundness, _shapeData_outerRoundness;
2310
+ options['pointCount'] = shapeData.pointCount;
2311
+ options['innerRadius'] = roundNumber(shapeData.innerRadius * ratio, 4);
2312
+ options['outerRadius'] = roundNumber(shapeData.outerRadius * ratio, 4);
2313
+ options['innerRoundness'] = (_shapeData_innerRoundness = shapeData.innerRoundness) != null ? _shapeData_innerRoundness : 0;
2314
+ options['outerRoundness'] = (_shapeData_outerRoundness = shapeData.outerRoundness) != null ? _shapeData_outerRoundness : 0;
2315
+ break;
2316
+ }
2322
2317
  if (shapeData.fills != null && shapeData.fills.length > 0) {
2323
2318
  options['fills'] = shapeData.fills.map(function(fill) {
2324
2319
  return mapShapePaint(fill, ratio, ctx);
@@ -2346,18 +2341,6 @@ function buildShapeOptions(shapeData, ratio, ctx) {
2346
2341
  if (shapeData.strokeJoin != null) {
2347
2342
  options['strokeJoin'] = mapLineJoin(shapeData.strokeJoin);
2348
2343
  }
2349
- if (shapeData.fillRule != null) {
2350
- options['fillRule'] = mapShapeFillRule(shapeData.fillRule);
2351
- }
2352
- if (shapeData.customPaths != null && shapeData.customPaths.length > 0) {
2353
- Object.assign(options, mapCustomPaths(shapeData.customPaths, ratio));
2354
- }
2355
- if (shapeData.trimPath != null) {
2356
- options['trimPath'] = shapeData.trimPath;
2357
- }
2358
- if (shapeData.repeater != null) {
2359
- options['repeater'] = shapeData.repeater;
2360
- }
2361
2344
  return options;
2362
2345
  }
2363
2346
  var _obj;
@@ -2368,8 +2351,6 @@ var _obj2;
2368
2351
  var LINE_CAP_TO_GE = (_obj2 = {}, _obj2[animationIr.IRLineCap.Butt] = 0, _obj2[animationIr.IRLineCap.Round] = 1, _obj2[animationIr.IRLineCap.Square] = 2, _obj2);
2369
2352
  var _obj3;
2370
2353
  var LINE_JOIN_TO_GE = (_obj3 = {}, _obj3[animationIr.IRLineJoin.Round] = 0, _obj3[animationIr.IRLineJoin.Bevel] = 1, _obj3[animationIr.IRLineJoin.Miter] = 2, _obj3);
2371
- var _obj4;
2372
- var SHAPE_FILL_RULE_TO_GE = (_obj4 = {}, _obj4[animationIr.IRShapeFillRule.NonZero] = 0, _obj4[animationIr.IRShapeFillRule.EvenOdd] = 1, _obj4);
2373
2354
  function mapShapePrimitiveType(primitiveType) {
2374
2355
  return SHAPE_PRIMITIVE_TYPE_TO_GE[primitiveType];
2375
2356
  }
@@ -2381,10 +2362,6 @@ function mapLineJoin(lineJoin) {
2381
2362
  var _LINE_JOIN_TO_GE_lineJoin;
2382
2363
  return (_LINE_JOIN_TO_GE_lineJoin = LINE_JOIN_TO_GE[lineJoin]) != null ? _LINE_JOIN_TO_GE_lineJoin : 2;
2383
2364
  }
2384
- function mapShapeFillRule(fillRule) {
2385
- var _SHAPE_FILL_RULE_TO_GE_fillRule;
2386
- return (_SHAPE_FILL_RULE_TO_GE_fillRule = SHAPE_FILL_RULE_TO_GE[fillRule]) != null ? _SHAPE_FILL_RULE_TO_GE_fillRule : 0;
2387
- }
2388
2365
  function mapShapePaint(paint, ratio, ctx) {
2389
2366
  if (paint.type === animationIr.IRFillType.Solid) {
2390
2367
  return {
@@ -2393,7 +2370,7 @@ function mapShapePaint(paint, ratio, ctx) {
2393
2370
  };
2394
2371
  }
2395
2372
  if (paint.type === animationIr.IRFillType.LinearGradient || paint.type === animationIr.IRFillType.RadialGradient || paint.type === animationIr.IRFillType.AngularGradient) {
2396
- return _extends({
2373
+ return {
2397
2374
  type: FILL_TYPE_TO_GE[paint.type],
2398
2375
  gradientStops: [
2399
2376
  ValueType.GRADIENT_COLOR,
@@ -2401,13 +2378,12 @@ function mapShapePaint(paint, ratio, ctx) {
2401
2378
  ],
2402
2379
  startPoint: vec2ToGE(paint.gradientStart, ratio),
2403
2380
  endPoint: vec2ToGE(paint.gradientEnd, ratio)
2404
- }, paint.color != null && {
2405
- color: colorToGE(paint.color)
2406
- });
2381
+ };
2407
2382
  }
2408
2383
  if (paint.type === animationIr.IRFillType.Texture) {
2409
- var _ref, _paint_texture_url, _paint_scaleMode;
2410
- var textureUrl = (_ref = (_paint_texture_url = paint.texture.url) != null ? _paint_texture_url : paint.texture.refId) != null ? _ref : paint.texture.id;
2384
+ var _paint_scaleMode;
2385
+ var textureAssetUrl = paint.texture.url;
2386
+ var textureUrl = textureAssetUrl != null && textureAssetUrl !== '' ? textureAssetUrl : paint.texture.refId;
2411
2387
  var texture = textureUrl != null && ctx != null ? registerTexture(ctx.collector, textureUrl, ctx.textureCache) : undefined;
2412
2388
  return _extends({
2413
2389
  type: FILL_TYPE_TO_GE[paint.type]
@@ -2445,8 +2421,8 @@ function mapCustomPaths(paths, ratio) {
2445
2421
  for(var index = 0; index < path.points.length; index++){
2446
2422
  var _ref, _ref1, _ref2, _ref3;
2447
2423
  var point = path.points[index];
2448
- var easingIn = path.easingIns[index];
2449
- var easingOut = path.easingOuts[index];
2424
+ var easingIn = path.inTangents[index];
2425
+ var easingOut = path.outTangents[index];
2450
2426
  var pointIndex = points.length;
2451
2427
  points.push({
2452
2428
  x: roundNumber(point.x * ratio, 4),
@@ -2467,7 +2443,7 @@ function mapCustomPaths(paths, ratio) {
2467
2443
  });
2468
2444
  }
2469
2445
  shapes.push({
2470
- close: path.close,
2446
+ close: path.closed,
2471
2447
  indexes: indexes
2472
2448
  });
2473
2449
  }
@@ -2478,100 +2454,54 @@ function mapCustomPaths(paths, ratio) {
2478
2454
  shapes: shapes
2479
2455
  };
2480
2456
  }
2481
- function setScaledNumber(options, shapeData, key, ratio) {
2482
- var value = shapeData[key];
2483
- if (typeof value === 'number') {
2484
- options[key] = roundNumber(value * ratio, 4);
2485
- }
2486
- }
2487
- function setRawNumber(options, shapeData, key) {
2488
- var value = shapeData[key];
2489
- if (typeof value === 'number') {
2490
- options[key] = value;
2491
- }
2492
- }
2493
2457
 
2494
- function getStaticAnchorBehavior(ir, layer) {
2495
- if (layer.transformSplit === true) {
2458
+ function planGELayerLowering(ir, layer) {
2459
+ var _getEffectsLayerSpecific;
2460
+ var sourceHierarchy = (_getEffectsLayerSpecific = getEffectsLayerSpecific(ir, layer)) == null ? void 0 : _getEffectsLayerSpecific.sourceHierarchy;
2461
+ if (sourceHierarchy === 'null-sprite-pair') {
2496
2462
  return {
2497
2463
  kind: 'split-null-sprite'
2498
2464
  };
2499
2465
  }
2500
- // B-class real semantic difference — kept as source branch because pre-baking
2501
- // anchorScale/anchorOffset into the IR would require pulling computeAnchorInfo's
2502
- // full input set (text anchorAdjust, static-rotation anchor rotation, display
2503
- // size fallback) into the producer, at high cost with no readability benefit.
2504
- // The split gate itself is already pre-baked via `transformSplit` above.
2505
- //
2506
- // ge source shares the lottie inline-anchor math: ge2ir reverses GE's
2507
- // `renderer.anchor` into IRLayerNode.transform.anchor (px) + displaySize, so
2508
- // computeAnchorInfo reproduces the exact anchorScale/anchorOffset that GE had.
2509
- // Without this, ge layers fall through to the centered [0.5,0.5] default and
2510
- // their authored anchor (e.g. a top-anchored sweep) is lost on round-trip.
2511
- // ge never reaches the lottieNeedsTransformSplit geometry check — its split
2512
- // decision is pre-baked via `transformSplit` by the ge2ir null+sprite merger.
2513
- if (ir.source === 'lottie' || ir.source === 'ge') {
2514
- if (ir.source === 'lottie' && lottieNeedsTransformSplit(layer)) {
2515
- return {
2516
- kind: 'split-null-sprite'
2517
- };
2518
- }
2519
- // The inline-anchor math needs non-zero dimensions to avoid divide-by-zero
2520
- // in `computeAnchorInfo`; substitute the legacy {1, 1} fallback at the call site
2521
- // so the field-level default stays neutral.
2522
- var _getLayerDisplaySize = getLayerDisplaySize(layer), width = _getLayerDisplaySize.width, height = _getLayerDisplaySize.height;
2523
- var info = computeAnchorInfo(layer, width, height);
2466
+ var bounds = getLayerLocalBounds(layer);
2467
+ if (sourceHierarchy !== 'single-item' && needsPivotContainer(layer, bounds)) {
2524
2468
  return {
2525
- kind: 'inline-anchor',
2526
- anchorScale: [
2527
- info.anchorScaleX,
2528
- info.anchorScaleY
2529
- ],
2530
- anchorOffset: [
2531
- info.anchorOffsetX,
2532
- info.anchorOffsetY
2533
- ]
2469
+ kind: 'split-null-sprite'
2534
2470
  };
2535
2471
  }
2536
- // dsl layers with off-center anchor have `transformSplit = true` set by the
2537
- // producer, caught by the guard at the top. Any layer reaching here is
2538
- // centered — return the default inline-anchor.
2472
+ var info = computeAnchorInfo(layer, bounds);
2539
2473
  return {
2540
2474
  kind: 'inline-anchor',
2541
2475
  anchorScale: [
2542
- 0.5,
2543
- 0.5
2476
+ info.anchorScaleX,
2477
+ info.anchorScaleY
2544
2478
  ],
2545
2479
  anchorOffset: [
2546
- 0,
2547
- 0
2480
+ info.anchorOffsetX,
2481
+ info.anchorOffsetY
2548
2482
  ]
2549
2483
  };
2550
2484
  }
2551
- function lottieNeedsTransformSplit(layer) {
2552
- var _transform_rotation, _sep_x, _sep_y, _sep_z, _transform_scale;
2485
+ function needsPivotContainer(layer, bounds) {
2486
+ var _rotation_x, _rotation_y, _rotation_z, _transform_scale;
2553
2487
  if (layer.type !== 'image' && layer.type !== 'solid') {
2554
2488
  return false;
2555
2489
  }
2556
- // Without a producer-baked displaySize we cannot decide off-center;
2557
- // fall through to inline-anchor (matches the pre-displaySize behavior
2558
- // where missing dimensions returned the {1, 1} default and never split).
2559
- var size = layer.displaySize;
2560
- if (size == null) {
2490
+ if (layer.localBounds == null) {
2561
2491
  return false;
2562
2492
  }
2563
- var width = size.width, height = size.height;
2493
+ var x = bounds.x, y = bounds.y, width = bounds.width, height = bounds.height;
2564
2494
  if (width <= 0 || height <= 0) {
2565
2495
  return false;
2566
2496
  }
2567
2497
  var anchor = getStaticAnchor(layer);
2568
- var anchorOffCenter = Math.abs(anchor[0] - width / 2) > 0.5 || Math.abs(anchor[1] - height / 2) > 0.5;
2498
+ var anchorOffCenter = Math.abs(anchor[0] - (x + width / 2)) > 0.5 || Math.abs(anchor[1] - (y + height / 2)) > 0.5;
2569
2499
  if (!anchorOffCenter) {
2570
2500
  return false;
2571
2501
  }
2572
2502
  var transform = layer.transform;
2573
- var sep = transform == null ? void 0 : transform.separatedRotation;
2574
- var hasRotationAnim = (transform == null ? void 0 : (_transform_rotation = transform.rotation) == null ? void 0 : _transform_rotation.keyframed) === true || (sep == null ? void 0 : (_sep_x = sep.x) == null ? void 0 : _sep_x.keyframed) === true || (sep == null ? void 0 : (_sep_y = sep.y) == null ? void 0 : _sep_y.keyframed) === true || (sep == null ? void 0 : (_sep_z = sep.z) == null ? void 0 : _sep_z.keyframed) === true;
2503
+ var rotation = transform == null ? void 0 : transform.rotation;
2504
+ var hasRotationAnim = (rotation == null ? void 0 : (_rotation_x = rotation.x) == null ? void 0 : _rotation_x.keyframed) === true || (rotation == null ? void 0 : (_rotation_y = rotation.y) == null ? void 0 : _rotation_y.keyframed) === true || (rotation == null ? void 0 : (_rotation_z = rotation.z) == null ? void 0 : _rotation_z.keyframed) === true;
2575
2505
  var hasScaleAnim = (transform == null ? void 0 : (_transform_scale = transform.scale) == null ? void 0 : _transform_scale.keyframed) === true;
2576
2506
  return hasRotationAnim || hasScaleAnim;
2577
2507
  }
@@ -2580,7 +2510,7 @@ function processNullLayer(layer, ctx) {
2580
2510
  var itemId = createId();
2581
2511
  var layerIndex = layer.index;
2582
2512
  ctx.layerToItemId[layerIndex] = itemId;
2583
- var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2513
+ var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate, ctx.ir.inPoint), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2584
2514
  var animation = buildTransformAnimation(layer, ctx);
2585
2515
  var position = computeStaticPosition(layer, ctx);
2586
2516
  var objectBindingTrackId = buildTimelineTracks(ctx.collector, delay, layerDuration, 4, animation, 'null');
@@ -2590,7 +2520,7 @@ function processNullLayer(layer, ctx) {
2590
2520
  name: layer.name,
2591
2521
  duration: layerDuration,
2592
2522
  type: '3',
2593
- visible: layer.visibility.enabled && !layer.visibility.hidden,
2523
+ visible: layer.visible,
2594
2524
  endBehavior: 4,
2595
2525
  delay: delay,
2596
2526
  renderLevel: 'B+',
@@ -2626,19 +2556,19 @@ function processPrecompLayer(layer, ctx) {
2626
2556
  var itemId = createId();
2627
2557
  var layerIndex = layer.index;
2628
2558
  ctx.layerToItemId[layerIndex] = itemId;
2629
- var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2559
+ var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate, ctx.ir.inPoint), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2630
2560
  var animation = buildTransformAnimation(layer, ctx);
2631
2561
  var position = computeStaticPosition(layer, ctx);
2632
2562
  var objectBindingTrackId = buildTimelineTracks(ctx.collector, delay, layerDuration, 4, animation, 'precomp');
2633
- var geMetadata = readGE2IRMetadata(ctx.ir, layer);
2634
- var content = buildPrecompContent(geMetadata == null ? void 0 : geMetadata.precompContent, geMetadata == null ? void 0 : geMetadata.precompRefId);
2563
+ var effectsSpecific = getEffectsLayerSpecific(ctx.ir, layer);
2564
+ var content = buildPrecompContent(effectsSpecific == null ? void 0 : effectsSpecific.precompContent, effectsSpecific == null ? void 0 : effectsSpecific.precompRefId);
2635
2565
  var item = {
2636
2566
  id: itemId,
2637
2567
  dataType: 'VFXItemData',
2638
2568
  name: layer.name,
2639
2569
  duration: layerDuration,
2640
2570
  type: '7',
2641
- visible: layer.visibility.enabled && !layer.visibility.hidden,
2571
+ visible: layer.visible,
2642
2572
  endBehavior: 4,
2643
2573
  delay: delay,
2644
2574
  renderLevel: 'B+',
@@ -2682,14 +2612,13 @@ function isRecord$3(value) {
2682
2612
  * the layer's logical position; the sprite/text child carries the visual
2683
2613
  * content offset by the anchor so the pivot is at the right point.
2684
2614
  *
2685
- * Used by both `processParentLayer` (layers referenced as `parent` by others)
2686
- * and `processTransformSplitLayer` (layers with `transformSplit=true`). The
2687
- * only knob is `childScale` — parent-layer callers pass a text-aware scale
2688
- * while transformSplit always uses `[1, 1, 1]`.
2689
- */ function emitNullSpritePair(layer, ctx, childScale) {
2615
+ * Used by both `processParentLayer` and GE lowering for layers that require a
2616
+ * pivot container.
2617
+ */ function emitNullSpritePair(layer, ctx) {
2690
2618
  var layerIndex = layer.index;
2691
- var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2692
- var _getLayerDisplaySize = getLayerDisplaySize(layer), layerWidth = _getLayerDisplaySize.width, layerHeight = _getLayerDisplaySize.height;
2619
+ var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate, ctx.ir.inPoint), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2620
+ var bounds = getLayerLocalBounds(layer);
2621
+ var x = bounds.x, y = bounds.y, layerWidth = bounds.width, layerHeight = bounds.height;
2693
2622
  var nullItemId = createId();
2694
2623
  ctx.layerToItemId[layerIndex] = nullItemId;
2695
2624
  var nullAnimation = buildTransformAnimation(layer, ctx);
@@ -2734,9 +2663,11 @@ function isRecord$3(value) {
2734
2663
  });
2735
2664
  var childItemId = createId();
2736
2665
  var anchor = getStaticAnchor(layer);
2666
+ var centerX = x + layerWidth / 2;
2667
+ var centerY = y + layerHeight / 2;
2737
2668
  var childPosition = [
2738
- -ctx.ratio * (anchor[0] - layerWidth / 2),
2739
- ctx.ratio * (anchor[1] - layerHeight / 2),
2669
+ -ctx.ratio * (anchor[0] - centerX),
2670
+ ctx.ratio * (anchor[1] - centerY),
2740
2671
  0
2741
2672
  ];
2742
2673
  var childColorAnim = buildColorAnimation(layer, ctx.ir);
@@ -2749,13 +2680,22 @@ function isRecord$3(value) {
2749
2680
  }
2750
2681
  var scaledW = roundNumber(ctx.ratio * layerWidth, 4);
2751
2682
  var scaledH = roundNumber(ctx.ratio * layerHeight, 4);
2683
+ var childScale = layer.type === 'text' ? [
2684
+ scaledW,
2685
+ scaledH,
2686
+ 1
2687
+ ] : [
2688
+ 1,
2689
+ 1,
2690
+ 1
2691
+ ];
2752
2692
  var childItem = {
2753
2693
  id: childItemId,
2754
2694
  dataType: 'VFXItemData',
2755
2695
  name: layer.name,
2756
2696
  duration: layerDuration,
2757
2697
  type: getGEItemTypeCode(layer.type),
2758
- visible: layer.visibility.enabled && !layer.visibility.hidden,
2698
+ visible: layer.visible,
2759
2699
  endBehavior: 0,
2760
2700
  delay: delay,
2761
2701
  renderLevel: 'B+',
@@ -2786,35 +2726,24 @@ function isRecord$3(value) {
2786
2726
  });
2787
2727
  }
2788
2728
  function processParentLayer(layer, ctx) {
2789
- var _getLayerDisplaySize = getLayerDisplaySize(layer), layerWidth = _getLayerDisplaySize.width, layerHeight = _getLayerDisplaySize.height;
2790
- var scaledW = roundNumber(ctx.ratio * layerWidth, 4);
2791
- var scaledH = roundNumber(ctx.ratio * layerHeight, 4);
2792
- var childScale = layer.type === 'text' ? [
2793
- scaledW,
2794
- scaledH,
2795
- 1
2796
- ] : [
2797
- 1,
2798
- 1,
2799
- 1
2800
- ];
2801
- emitNullSpritePair(layer, ctx, childScale);
2729
+ emitNullSpritePair(layer, ctx);
2802
2730
  }
2803
2731
  function processVisualLayer(layer, ctx) {
2804
- if (layer.type === 'shape' && layer.shapes != null && layer.shapes.length > 0) {
2805
- processShapeLayerMultiItem(layer, ctx);
2732
+ var strategy = planGELayerLowering(ctx.ir, layer);
2733
+ if (strategy.kind === 'split-null-sprite') {
2734
+ processPivotContainerLayer(layer, ctx);
2806
2735
  return;
2807
2736
  }
2808
- var strategy = getStaticAnchorBehavior(ctx.ir, layer);
2809
- if (strategy.kind === 'split-null-sprite') {
2810
- processTransformSplitLayer(layer, ctx);
2737
+ if (layer.type === 'shape' && layer.shapes != null && layer.shapes.length > 0) {
2738
+ processShapeLayerMultiItem(layer, ctx);
2811
2739
  return;
2812
2740
  }
2813
2741
  var itemId = createId();
2814
2742
  var layerIndex = layer.index;
2815
2743
  ctx.layerToItemId[layerIndex] = itemId;
2816
- var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2817
- var _getLayerDisplaySize = getLayerDisplaySize(layer), layerWidth = _getLayerDisplaySize.width, layerHeight = _getLayerDisplaySize.height;
2744
+ var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate, ctx.ir.inPoint), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2745
+ var bounds = getLayerLocalBounds(layer);
2746
+ var layerWidth = bounds.width, layerHeight = bounds.height;
2818
2747
  var scaledW = ctx.ratio * layerWidth;
2819
2748
  var scaledH = ctx.ratio * layerHeight;
2820
2749
  var _strategy_anchorScale = strategy.anchorScale, anchorScaleX = _strategy_anchorScale[0], anchorScaleY = _strategy_anchorScale[1];
@@ -2825,7 +2754,7 @@ function processVisualLayer(layer, ctx) {
2825
2754
  colorOverLifetime: colorAnimation
2826
2755
  });
2827
2756
  var rawPosition = computeStaticPosition(layer, ctx, anchorOffsetX, anchorOffsetY);
2828
- var position = applyScalePositionAdjust(rawPosition, layer, layerWidth, layerHeight, ctx.ratio);
2757
+ var position = applyScalePositionAdjust(rawPosition, layer, bounds, ctx.ratio);
2829
2758
  var itemType = getGEItemType(layer.type);
2830
2759
  var objectBindingTrackId = buildTimelineTracks(ctx.collector, delay, layerDuration, 0, fullAnimation, itemType);
2831
2760
  var componentId = buildComponent(layer, itemId, anchorScaleX, anchorScaleY, ctx);
@@ -2852,7 +2781,7 @@ function processVisualLayer(layer, ctx) {
2852
2781
  name: layer.name,
2853
2782
  duration: layerDuration,
2854
2783
  type: getGEItemTypeCode(layer.type),
2855
- visible: layer.visibility.enabled && !layer.visibility.hidden,
2784
+ visible: layer.visible,
2856
2785
  endBehavior: 0,
2857
2786
  delay: delay,
2858
2787
  renderLevel: 'B+',
@@ -2881,19 +2810,24 @@ function processVisualLayer(layer, ctx) {
2881
2810
  layerIndex: layerIndex
2882
2811
  });
2883
2812
  }
2884
- function processTransformSplitLayer(layer, ctx) {
2885
- emitNullSpritePair(layer, ctx, [
2886
- 1,
2887
- 1,
2888
- 1
2889
- ]);
2813
+ function processPivotContainerLayer(layer, ctx) {
2814
+ emitNullSpritePair(layer, ctx);
2890
2815
  }
2891
2816
  function processShapeLayerMultiItem(layer, ctx) {
2892
2817
  var layerIndex = layer.index;
2893
- var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2894
- var _getLayerDisplaySize = getLayerDisplaySize(layer), layerWidth = _getLayerDisplaySize.width, layerHeight = _getLayerDisplaySize.height;
2818
+ var _computeLayerTiming = computeLayerTiming(layer, ctx.frameRate, ctx.ir.inPoint), delay = _computeLayerTiming.delay, layerDuration = _computeLayerTiming.layerDuration;
2819
+ // A GE Shape item commonly has no transform.size, so ge2ir cannot recover
2820
+ // layer-local bounds. Treat missing bounds as empty here: the generic 1×1
2821
+ // fallback would invent a half-pixel anchor offset and shift every rebuilt
2822
+ // shape (notably mask sources) away from its authored position.
2823
+ var bounds = getLayerLocalBounds(layer, {
2824
+ x: 0,
2825
+ y: 0,
2826
+ width: 0,
2827
+ height: 0
2828
+ });
2895
2829
  var anchor = getStaticAnchor(layer);
2896
- var _computeAnchorInfo = computeAnchorInfo(layer, layerWidth, layerHeight), anchorOffsetX = _computeAnchorInfo.anchorOffsetX, anchorOffsetY = _computeAnchorInfo.anchorOffsetY;
2830
+ var _computeAnchorInfo = computeAnchorInfo(layer, bounds), anchorOffsetX = _computeAnchorInfo.anchorOffsetX, anchorOffsetY = _computeAnchorInfo.anchorOffsetY;
2897
2831
  var animation = buildTransformAnimation(layer, ctx);
2898
2832
  var colorAnimation = buildColorAnimation(layer, ctx.ir);
2899
2833
  var fullAnimation = _extends({}, animation, {
@@ -2928,7 +2862,7 @@ function processShapeLayerMultiItem(layer, ctx) {
2928
2862
  });
2929
2863
  // Mask source shape (isMask:true) — copy onto the first shape item only.
2930
2864
  if (shapeIdx === 0) {
2931
- applyGeMask(ctx.ir, layer, component);
2865
+ applyGEMask(ctx.ir, layer, component);
2932
2866
  }
2933
2867
  ctx.collector.components.push(component);
2934
2868
  if (shapeIdx === 0) {
@@ -2941,7 +2875,7 @@ function processShapeLayerMultiItem(layer, ctx) {
2941
2875
  name: shapeIdx === 0 ? layer.name : layer.name + "_shape_" + shapeIdx,
2942
2876
  duration: layerDuration,
2943
2877
  type: 'shape',
2944
- visible: layer.visibility.enabled && !layer.visibility.hidden,
2878
+ visible: layer.visible,
2945
2879
  endBehavior: 0,
2946
2880
  delay: delay,
2947
2881
  renderLevel: 'B+',
@@ -3074,16 +3008,20 @@ function deriveDuration(ir) {
3074
3008
  }
3075
3009
  /**
3076
3010
  * Map IR composition end behavior to GE's numeric end-behavior.
3077
- * Lottie IR currently leaves this unset; treat undefined as Loop (5) so the
3078
- * legacy lottie behavior is preserved. dsl2ge writes either Loop or Stop.
3011
+ * Undefined defaults to Restart (5) for backward compatibility. DSL's boolean
3012
+ * loop flag maps to either Restart or Destroy at the adapter boundary.
3079
3013
  */ function mapCompositionEndBehavior(eb) {
3080
- if (eb == null || eb === animationIr.IREndBehavior.Loop) {
3081
- return 5;
3082
- }
3083
- if (eb === animationIr.IREndBehavior.Hold) {
3084
- return 4;
3014
+ switch(eb){
3015
+ case undefined:
3016
+ case animationIr.IREndBehavior.Restart:
3017
+ return 5;
3018
+ case animationIr.IREndBehavior.Forward:
3019
+ return 2;
3020
+ case animationIr.IREndBehavior.Freeze:
3021
+ return 4;
3022
+ case animationIr.IREndBehavior.Destroy:
3023
+ return 0;
3085
3024
  }
3086
- return 0;
3087
3025
  }
3088
3026
  function colorToRoundedRgba(color) {
3089
3027
  return [
@@ -3154,13 +3092,10 @@ function applyMasks(ir, collector, processedItems, ratio, width, height, frameRa
3154
3092
  continue;
3155
3093
  }
3156
3094
  var layerComponentId = lookup.getComponentId(layer.index);
3157
- buildMaskForLayer(layer, layerItemId, layerComponentId, collector, processedItems, ratio, width, height, frameRate, lookup, maskSlotMeta, componentById, maskData);
3095
+ buildMaskForLayer(layer, layerItemId, layerComponentId, collector, processedItems, ratio, width, height, frameRate, ir.inPoint, lookup, maskSlotMeta, componentById, maskData);
3158
3096
  }
3159
3097
  }
3160
- function getPrimaryPath(mask) {
3161
- return mask.paths[0];
3162
- }
3163
- function buildMaskForLayer(layer, layerItemId, layerComponentId, collector, processedItems, ratio, width, height, frameRate, lookup, maskSlotMeta, componentById, maskData) {
3098
+ function buildMaskForLayer(layer, layerItemId, layerComponentId, collector, processedItems, ratio, width, height, frameRate, compositionInPoint, lookup, maskSlotMeta, componentById, maskData) {
3164
3099
  var mask = maskData != null ? maskData : layer.mask;
3165
3100
  var maskItemId = createId();
3166
3101
  var maskComponentId = createId();
@@ -3168,7 +3103,7 @@ function buildMaskForLayer(layer, layerItemId, layerComponentId, collector, proc
3168
3103
  var _getStaticAnchor = getStaticAnchor(layer), anchorX = _getStaticAnchor[0], anchorY = _getStaticAnchor[1];
3169
3104
  var maskPosX = roundNumber((maskBounds.cx - anchorX) * ratio, 4);
3170
3105
  var maskPosY = roundNumber(-(maskBounds.cy - anchorY) * ratio, 4);
3171
- var timing = computeLayerTiming(layer, frameRate);
3106
+ var timing = computeLayerTiming(layer, frameRate, compositionInPoint);
3172
3107
  var delay = timing.delay;
3173
3108
  var maskDuration = timing.layerDuration;
3174
3109
  var layerIsParent = lookup.isParentLayer(layer.index) || layer.type === 'null' || layer.type === 'precomp';
@@ -3360,8 +3295,8 @@ function computePointBounds(points) {
3360
3295
  };
3361
3296
  }
3362
3297
  function isMaskExactCrop(mask, layer, width, height, lookup) {
3363
- var path = getPrimaryPath(mask);
3364
- if (path == null || path.points.length === 0) {
3298
+ var path = mask.path;
3299
+ if (path.points.length === 0) {
3365
3300
  return true;
3366
3301
  }
3367
3302
  var _computePointBounds = computePointBounds(path.points), minX = _computePointBounds.minX, minY = _computePointBounds.minY, maxX = _computePointBounds.maxX, maxY = _computePointBounds.maxY;
@@ -3386,8 +3321,8 @@ function isMaskExactCrop(mask, layer, width, height, lookup) {
3386
3321
  return false;
3387
3322
  }
3388
3323
  function getMaskBounds(mask) {
3389
- var path = getPrimaryPath(mask);
3390
- if (path == null || path.points.length === 0) {
3324
+ var path = mask.path;
3325
+ if (path.points.length === 0) {
3391
3326
  return {
3392
3327
  cx: 0,
3393
3328
  cy: 0,
@@ -3404,47 +3339,41 @@ function getMaskBounds(mask) {
3404
3339
  };
3405
3340
  }
3406
3341
  function isSimpleRectMask(mask) {
3407
- var path = getPrimaryPath(mask);
3408
- if (path == null) {
3409
- return false;
3410
- }
3411
- return path.points.length === 4 && path.easingIns.every(function(e) {
3412
- return Math.abs(e.x) < 0.01 && Math.abs(e.y) < 0.01;
3413
- }) && path.easingOuts.every(function(e) {
3414
- return Math.abs(e.x) < 0.01 && Math.abs(e.y) < 0.01;
3342
+ var path = mask.path;
3343
+ return path.points.length === 4 && path.inTangents.every(function(tangent) {
3344
+ return Math.abs(tangent.x) < 0.01 && Math.abs(tangent.y) < 0.01;
3345
+ }) && path.outTangents.every(function(tangent) {
3346
+ return Math.abs(tangent.x) < 0.01 && Math.abs(tangent.y) < 0.01;
3415
3347
  });
3416
3348
  }
3417
3349
  function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ratio) {
3418
- var _ref;
3419
- var path = getPrimaryPath(mask);
3350
+ var path = mask.path;
3420
3351
  var customPoints = [];
3421
3352
  var customEasingIns = [];
3422
3353
  var customEasingOuts = [];
3423
3354
  var customIndexes = [];
3424
- if (path != null) {
3425
- for(var idx = 0; idx < path.points.length; idx++){
3426
- var _ref1, _ref2, _ref3, _ref4;
3427
- var pt = path.points[idx];
3428
- var ei = path.easingIns[idx];
3429
- var eo = path.easingOuts[idx];
3430
- customPoints.push({
3431
- x: roundNumber((pt.x - bounds.cx) * ratio, 4),
3432
- y: roundNumber(-(pt.y - bounds.cy) * ratio, 4)
3433
- });
3434
- customEasingIns.push({
3435
- x: roundNumber(((_ref1 = ei == null ? void 0 : ei.x) != null ? _ref1 : 0) * ratio, 4),
3436
- y: roundNumber(-((_ref2 = ei == null ? void 0 : ei.y) != null ? _ref2 : 0) * ratio, 4)
3437
- });
3438
- customEasingOuts.push({
3439
- x: roundNumber(((_ref3 = eo == null ? void 0 : eo.x) != null ? _ref3 : 0) * ratio, 4),
3440
- y: roundNumber(-((_ref4 = eo == null ? void 0 : eo.y) != null ? _ref4 : 0) * ratio, 4)
3441
- });
3442
- customIndexes.push({
3443
- point: idx,
3444
- easingIn: idx,
3445
- easingOut: idx
3446
- });
3447
- }
3355
+ for(var idx = 0; idx < path.points.length; idx++){
3356
+ var _ref, _ref1, _ref2, _ref3;
3357
+ var pt = path.points[idx];
3358
+ var ei = path.inTangents[idx];
3359
+ var eo = path.outTangents[idx];
3360
+ customPoints.push({
3361
+ x: roundNumber((pt.x - bounds.cx) * ratio, 4),
3362
+ y: roundNumber(-(pt.y - bounds.cy) * ratio, 4)
3363
+ });
3364
+ customEasingIns.push({
3365
+ x: roundNumber(((_ref = ei == null ? void 0 : ei.x) != null ? _ref : 0) * ratio, 4),
3366
+ y: roundNumber(-((_ref1 = ei == null ? void 0 : ei.y) != null ? _ref1 : 0) * ratio, 4)
3367
+ });
3368
+ customEasingOuts.push({
3369
+ x: roundNumber(((_ref2 = eo == null ? void 0 : eo.x) != null ? _ref2 : 0) * ratio, 4),
3370
+ y: roundNumber(-((_ref3 = eo == null ? void 0 : eo.y) != null ? _ref3 : 0) * ratio, 4)
3371
+ });
3372
+ customIndexes.push({
3373
+ point: idx,
3374
+ easingIn: idx,
3375
+ easingOut: idx
3376
+ });
3448
3377
  }
3449
3378
  return {
3450
3379
  id: maskComponentId,
@@ -3456,7 +3385,7 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3456
3385
  easingOuts: customEasingOuts,
3457
3386
  shapes: [
3458
3387
  {
3459
- close: (_ref = path == null ? void 0 : path.close) != null ? _ref : true,
3388
+ close: path.closed,
3460
3389
  indexes: customIndexes
3461
3390
  }
3462
3391
  ],
@@ -3489,10 +3418,10 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3489
3418
  * Remap GE mask references after ge2ir round-trip.
3490
3419
  *
3491
3420
  * ge2ir carries each masked component's raw `mask` object verbatim (via
3492
- * `IRLayerNode.metadata.ge2ir.geMask`), but `mask.reference.id` still points at the
3421
+ * `IRLayerNode.specific.effects.mask`), but `mask.reference.id` still points at the
3493
3422
  * ORIGINAL (GE1) mask-source component id, which ir2ge has regenerated. This
3494
3423
  * pass rewrites every target's `reference.id` from the stale GE1 id to the
3495
- * freshly-minted GE2 component id, using the `geComponentId → newId` map built
3424
+ * freshly-minted GE2 component id, using the `GEComponentId → newId` map built
3496
3425
  * during the layer walk.
3497
3426
  *
3498
3427
  * Mirrors `applyParenting`: an IR-side reference (here the stale id stored in
@@ -3500,7 +3429,7 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3500
3429
  * no `reference` and are skipped. Dangling references (source not regenerated —
3501
3430
  * e.g. dropped by the null+sprite merger) have their `mask` removed so the GE
3502
3431
  * runtime doesn't choke on an id that resolves to nothing.
3503
- */ function applyGeMaskRemap(collector, geComponentIdToNewId) {
3432
+ */ function applyGEMaskRemap(collector, GEComponentIdToNewId) {
3504
3433
  for(var _iterator = _create_for_of_iterator_helper_loose(collector.components), _step; !(_step = _iterator()).done;){
3505
3434
  var component = _step.value;
3506
3435
  var mask = component['mask'];
@@ -3512,7 +3441,7 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3512
3441
  if (oldId == null) {
3513
3442
  continue;
3514
3443
  }
3515
- var newId = geComponentIdToNewId[oldId];
3444
+ var newId = GEComponentIdToNewId[oldId];
3516
3445
  if (newId == null) {
3517
3446
  // Dangling: the referenced source was not regenerated. Drop the mask so
3518
3447
  // the target renders unmasked rather than referencing a nonexistent id.
@@ -3527,15 +3456,15 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3527
3456
  * Normalize child visibility delays so children never appear before their parent.
3528
3457
  *
3529
3458
  * Topologically sorts items (parent-first) so by the time we process any child
3530
- * its parent's delay/duration are already finalized. For transform-only
3531
- * parent-link children, we instead advance the parent's delay/duration so the
3459
+ * its parent's delay/duration are already finalized. For children with an
3460
+ * independent lifetime, we instead advance the parent's delay/duration so the
3532
3461
  * child can render from its own start time (GE requires the parent to be active
3533
3462
  * for transform inheritance, but the parent-link relationship does not propagate
3534
3463
  * visibility). Only the ActivationTrack clip is updated; TransformTrack
3535
3464
  * keyframes are normalized to the original time range and would hold their
3536
3465
  * first frame value if the track started earlier.
3537
3466
  */ function normalizeChildVisibilityByParentDelays(param) {
3538
- var items = param.items, miscs = param.miscs, processedItems = param.processedItems, _param_transformOnlyParentLinkItemIds = param.transformOnlyParentLinkItemIds, transformOnlyParentLinkItemIds = _param_transformOnlyParentLinkItemIds === void 0 ? new Set() : _param_transformOnlyParentLinkItemIds, roundNumber = param.roundNumber;
3467
+ var items = param.items, miscs = param.miscs, processedItems = param.processedItems, _param_independentLifetimeChildItemIds = param.independentLifetimeChildItemIds, independentLifetimeChildItemIds = _param_independentLifetimeChildItemIds === void 0 ? new Set() : _param_independentLifetimeChildItemIds, roundNumber = param.roundNumber;
3539
3468
  var itemById = new Map();
3540
3469
  for(var _iterator = _create_for_of_iterator_helper_loose(items), _step; !(_step = _iterator()).done;){
3541
3470
  var item = _step.value;
@@ -3551,9 +3480,9 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3551
3480
  var misc = _step2.value;
3552
3481
  miscById.set(misc['id'], misc);
3553
3482
  }
3554
- // Phase 1: Advance transform-only parent-link parents so their children can
3483
+ // Phase 1: Advance transform parents so independent-lifetime children can
3555
3484
  // render from the child's own start time.
3556
- advanceTransformOnlyParentLinkParents(items, itemById, processedByItemId, miscById, transformOnlyParentLinkItemIds, roundNumber);
3485
+ advanceIndependentLifetimeParents(items, itemById, processedByItemId, miscById, independentLifetimeChildItemIds, roundNumber);
3557
3486
  // Phase 2: Normalize precomp child visibility (unchanged).
3558
3487
  var effectiveDelayCache = new Map();
3559
3488
  function getEffectiveDelay(itemId, visited) {
@@ -3615,8 +3544,8 @@ function buildPolygonMaskComponent(maskComponentId, maskItemId, mask, bounds, ra
3615
3544
  syncTimelineClips(itemId, effectiveDelay, newDuration, processedByItemId, miscById, roundNumber);
3616
3545
  }
3617
3546
  }
3618
- function advanceTransformOnlyParentLinkParents(items, itemById, processedByItemId, miscById, transformOnlyParentLinkItemIds, roundNumber) {
3619
- if (transformOnlyParentLinkItemIds.size === 0) {
3547
+ function advanceIndependentLifetimeParents(items, itemById, processedByItemId, miscById, independentLifetimeChildItemIds, roundNumber) {
3548
+ if (independentLifetimeChildItemIds.size === 0) {
3620
3549
  return;
3621
3550
  }
3622
3551
  // Collect the maximum advance (head) and extension (tail) needed per parent.
@@ -3625,7 +3554,7 @@ function advanceTransformOnlyParentLinkParents(items, itemById, processedByItemI
3625
3554
  for(var _iterator = _create_for_of_iterator_helper_loose(items), _step; !(_step = _iterator()).done;){
3626
3555
  var item = _step.value;
3627
3556
  var _item_delay, _item_duration, _parentItem_delay, _parentItem_duration;
3628
- if (!transformOnlyParentLinkItemIds.has(item['id'])) {
3557
+ if (!independentLifetimeChildItemIds.has(item['id'])) {
3629
3558
  continue;
3630
3559
  }
3631
3560
  var parentId = item['parentId'];
@@ -3761,18 +3690,18 @@ function syncTimelineClips(itemId, delay, duration, processedByItemId, miscById,
3761
3690
  */ function applyPostProcess(ir, state) {
3762
3691
  applyParentingStep(ir, state);
3763
3692
  applySharedMaskPostProcess(ir, state);
3764
- applyGeMaskRemapStep(ir, state);
3693
+ applyGEMaskRemapStep(ir, state);
3765
3694
  applyVisibilityStep(ir, state);
3766
3695
  }
3767
- function applyGeMaskRemapStep(ir, state) {
3768
- // Only ge-sourced compositions carry passthrough mask references that need
3696
+ function applyGEMaskRemapStep(ir, state) {
3697
+ // Only Effects-sourced compositions carry passthrough mask references that need
3769
3698
  // remapping. Lottie/dsl masks are built with correct ids by applyMasks and
3770
- // must not be touched (their reference ids are absent from the ge map, so a
3699
+ // must not be touched (their reference ids are absent from the GE map, so a
3771
3700
  // blind remap would wrongly delete them).
3772
- if (ir.source !== 'ge' || state.geComponentIdToNewId == null) {
3701
+ if (ir.source !== 'effects' || state.GEComponentIdToNewId == null) {
3773
3702
  return;
3774
3703
  }
3775
- applyGeMaskRemap(state.collector, state.geComponentIdToNewId);
3704
+ applyGEMaskRemap(state.collector, state.GEComponentIdToNewId);
3776
3705
  }
3777
3706
  function applySharedMaskPostProcess(ir, state) {
3778
3707
  if (state.maskLookup == null || state.ratio == null || state.width == null || state.height == null || state.frameRate == null) {
@@ -3792,13 +3721,13 @@ function applyVisibilityStep(ir, state) {
3792
3721
  if (layerToItemId == null) {
3793
3722
  return;
3794
3723
  }
3795
- var transformOnlyParentLinkItemIds = new Set();
3724
+ var independentLifetimeChildItemIds = new Set();
3796
3725
  for(var _iterator = _create_for_of_iterator_helper_loose(ir.layers), _step; !(_step = _iterator()).done;){
3797
3726
  var layer = _step.value;
3798
- if (isTransformOnlyParentLink(layer)) {
3727
+ if (hasIndependentParentLifetime(layer)) {
3799
3728
  var itemId = layerToItemId[layer.index];
3800
3729
  if (itemId != null) {
3801
- transformOnlyParentLinkItemIds.add(itemId);
3730
+ independentLifetimeChildItemIds.add(itemId);
3802
3731
  }
3803
3732
  }
3804
3733
  }
@@ -3806,7 +3735,7 @@ function applyVisibilityStep(ir, state) {
3806
3735
  items: collector.items,
3807
3736
  miscs: collector.miscs,
3808
3737
  processedItems: processedItems,
3809
- transformOnlyParentLinkItemIds: transformOnlyParentLinkItemIds,
3738
+ independentLifetimeChildItemIds: independentLifetimeChildItemIds,
3810
3739
  roundNumber: roundNumber
3811
3740
  });
3812
3741
  }
@@ -3863,16 +3792,15 @@ function normalize(value, path, inArray) {
3863
3792
  * Convert an IR composition to a GE JSONScene.
3864
3793
  *
3865
3794
  * All IR sources (lottie, dsl, future) go through this single unified
3866
- * pipeline. Source-specific features are gated by data existence (e.g. mask,
3867
- * precomp, shape layers are absent in dsl IR and naturally skipped);
3868
- * `ir.source` branches are used only for B-class real semantic differences
3869
- * that cannot be expressed via data existence.
3795
+ * pipeline. Normalized animation semantics select the GE lowering plan;
3796
+ * source-specific payloads may preserve authored GE hierarchy or restore
3797
+ * mask and precomp graphs.
3870
3798
  *
3871
3799
  * The optional `duration` arg is a caller override; lottie2ge currently passes
3872
3800
  * the duration computed from the raw json upstream. When omitted, the
3873
3801
  * canonical assembler derives it from `(outPoint - inPoint) / frameRate`.
3874
3802
  */ function convertIRToGE(ir, duration) {
3875
- animationIr.validateIRCompositionWithWarnings(ir);
3803
+ animationIr.validateIRCompositionOrThrow(ir);
3876
3804
  var width = ir.width, height = ir.height, frameRate = ir.frameRate;
3877
3805
  var ratio = get2dTo3dRatio(width, height);
3878
3806
  var collector = {
@@ -3915,15 +3843,15 @@ function normalize(value, path, inArray) {
3915
3843
  }
3916
3844
  // Build GE1-component-id → regenerated-component-id map for mask reference
3917
3845
  // remapping (ge2ir round-trip). Keyed by the original GE component id that
3918
- // ge2ir stored in metadata; value is the component id this layer minted.
3919
- var geComponentIdToNewId = {};
3846
+ // ge2ir stored in specific.effects; value is the component id this layer minted.
3847
+ var GEComponentIdToNewId = {};
3920
3848
  for(var _iterator2 = _create_for_of_iterator_helper_loose(workingIR.layers), _step2; !(_step2 = _iterator2()).done;){
3921
3849
  var layer2 = _step2.value;
3922
- var _readGE2IRMetadata;
3923
- var geComponentId = (_readGE2IRMetadata = readGE2IRMetadata(workingIR, layer2)) == null ? void 0 : _readGE2IRMetadata.geComponentId;
3850
+ var _getEffectsLayerSpecific;
3851
+ var GEComponentId = (_getEffectsLayerSpecific = getEffectsLayerSpecific(workingIR, layer2)) == null ? void 0 : _getEffectsLayerSpecific.sourceComponentId;
3924
3852
  var newId = layerToComponentId[layer2.index];
3925
- if (geComponentId != null && newId != null) {
3926
- geComponentIdToNewId[geComponentId] = newId;
3853
+ if (GEComponentId != null && newId != null) {
3854
+ GEComponentIdToNewId[GEComponentId] = newId;
3927
3855
  }
3928
3856
  }
3929
3857
  applyPostProcess(workingIR, {
@@ -3934,7 +3862,7 @@ function normalize(value, path, inArray) {
3934
3862
  width: width,
3935
3863
  height: height,
3936
3864
  frameRate: frameRate,
3937
- geComponentIdToNewId: geComponentIdToNewId,
3865
+ GEComponentIdToNewId: GEComponentIdToNewId,
3938
3866
  maskLookup: {
3939
3867
  getItemId: function getItemId(idx) {
3940
3868
  return layerToItemId[idx];
@@ -3967,16 +3895,16 @@ function processLayer(layer, ctx) {
3967
3895
  }
3968
3896
  }
3969
3897
  function hasGEPrecompMetadata(ir, layer) {
3970
- var metadata = readGE2IRMetadata(ir, layer);
3971
- return (metadata == null ? void 0 : metadata.precompRefId) != null || (metadata == null ? void 0 : metadata.precompContent) != null;
3898
+ var specific = getEffectsLayerSpecific(ir, layer);
3899
+ return (specific == null ? void 0 : specific.precompRefId) != null || (specific == null ? void 0 : specific.precompContent) != null;
3972
3900
  }
3973
3901
  /**
3974
- * Extend parent layers' endFrame to cover transform-only children's time spans.
3902
+ * Extend parent layers' endFrame to cover independent child lifetimes.
3975
3903
  *
3976
3904
  * In Lottie, child layers (linked via layer.parent) inherit the parent's transform
3977
3905
  * even after the parent becomes invisible. GE requires the parent item to be active
3978
3906
  * for transform inheritance to work, so we extend the parent's endFrame to cover
3979
- * the full lifetime of its transform-only children.
3907
+ * the full lifetime of children whose lifetime is independent.
3980
3908
  *
3981
3909
  * Keyframes beyond the extended endFrame are NOT included — they represent animation
3982
3910
  * that never plays in Lottie (layer is invisible and has no child needing it).
@@ -3995,7 +3923,7 @@ function hasGEPrecompMetadata(ir, layer) {
3995
3923
  for(var _iterator1 = _create_for_of_iterator_helper_loose(clonedLayers), _step1; !(_step1 = _iterator1()).done;){
3996
3924
  var child = _step1.value;
3997
3925
  var _child_parent;
3998
- if (((_child_parent = child.parent) == null ? void 0 : _child_parent.index) === layer.index && child.parent.linkKind === 'transform-only') {
3926
+ if (((_child_parent = child.parent) == null ? void 0 : _child_parent.index) === layer.index && child.parent.lifetimeMode === 'independent') {
3999
3927
  if (child.time.endFrame > maxEnd) {
4000
3928
  maxEnd = child.time.endFrame;
4001
3929
  }
@@ -4014,13 +3942,13 @@ function mergePreservedPrecompScene(generated, ir) {
4014
3942
  return !isExcludedPoolEntry(pool, entry, excluded);
4015
3943
  }));
4016
3944
  };
4017
- var metadata = readGE2IRCompositionMetadata(ir);
4018
- var sourceScene = metadata == null ? void 0 : metadata.sourceScene;
3945
+ var specific = getEffectsCompositionSpecific(ir);
3946
+ var sourceScene = specific == null ? void 0 : specific.sourceScene;
4019
3947
  if (sourceScene == null) {
4020
3948
  return generated;
4021
3949
  }
4022
3950
  var result = _extends({}, generated);
4023
- var sourceCompositionId = metadata == null ? void 0 : metadata.sourceCompositionId;
3951
+ var sourceCompositionId = specific == null ? void 0 : specific.sourceCompositionId;
4024
3952
  var excluded = collectRootCompositionIds(sourceScene, sourceCompositionId);
4025
3953
  var pools = [
4026
3954
  'images',
@@ -4240,23 +4168,25 @@ function resolveDataPathId(ref) {
4240
4168
  return typeof id === 'string' ? id : undefined;
4241
4169
  }
4242
4170
 
4243
- function reverseEndBehavior(geBehavior) {
4244
- if (geBehavior == null) {
4171
+ function reverseEndBehavior(GEBehavior) {
4172
+ if (GEBehavior == null) {
4245
4173
  return undefined;
4246
4174
  }
4247
- switch(geBehavior){
4175
+ switch(GEBehavior){
4248
4176
  case 0:
4249
- return animationIr.IREndBehavior.Stop;
4177
+ return animationIr.IREndBehavior.Destroy;
4178
+ case 2:
4179
+ return animationIr.IREndBehavior.Forward;
4250
4180
  case 4:
4251
- return animationIr.IREndBehavior.Hold;
4181
+ return animationIr.IREndBehavior.Freeze;
4252
4182
  case 5:
4253
- return animationIr.IREndBehavior.Loop;
4183
+ return animationIr.IREndBehavior.Restart;
4254
4184
  default:
4255
4185
  return undefined;
4256
4186
  }
4257
4187
  }
4258
- function reverseCompositionEndBehavior(geBehavior) {
4259
- return reverseEndBehavior(geBehavior);
4188
+ function reverseCompositionEndBehavior(GEBehavior) {
4189
+ return reverseEndBehavior(GEBehavior);
4260
4190
  }
4261
4191
 
4262
4192
  function buildSceneContext(scene, options) {
@@ -4276,7 +4206,10 @@ function buildSceneContext(scene, options) {
4276
4206
  var frameRate = options.frameRate;
4277
4207
  var ratio = get2dTo3dRatio(width, height);
4278
4208
  var inPoint = 0;
4279
- var outPoint = Math.round(duration * frameRate);
4209
+ // GE durations are expressed in seconds and are not guaranteed to land on
4210
+ // an integer frame. Preserve the fractional frame so GE → IR → GE does not
4211
+ // shorten or extend the composition at the tail.
4212
+ var outPoint = duration * frameRate;
4280
4213
  var endBehavior = reverseCompositionEndBehavior(composition['endBehavior']);
4281
4214
  var backgroundColor;
4282
4215
  var bg = composition['background'];
@@ -4484,16 +4417,26 @@ function parseStaticTransform(itemTransform, ctx) {
4484
4417
  }
4485
4418
  var eulerHint = itemTransform['eulerHint'];
4486
4419
  if (eulerHint != null) {
4487
- var hasRotation = Math.abs(eulerHint.x) > 1e-6 || Math.abs(eulerHint.y) > 1e-6 || Math.abs(eulerHint.z) > 1e-6;
4488
- if (hasRotation) {
4489
- channels.rotation = {
4490
- keyframed: false,
4491
- value: [
4492
- eulerHint.x,
4493
- eulerHint.y,
4494
- eulerHint.z
4495
- ]
4496
- };
4420
+ var x = Math.abs(eulerHint.x) > 1e-6 ? {
4421
+ keyframed: false,
4422
+ value: eulerHint.x
4423
+ } : undefined;
4424
+ var y = Math.abs(eulerHint.y) > 1e-6 ? {
4425
+ keyframed: false,
4426
+ value: eulerHint.y
4427
+ } : undefined;
4428
+ var z = Math.abs(eulerHint.z) > 1e-6 ? {
4429
+ keyframed: false,
4430
+ value: eulerHint.z
4431
+ } : undefined;
4432
+ if (x != null || y != null || z != null) {
4433
+ channels.rotation = _extends({}, x != null && {
4434
+ x: x
4435
+ }, y != null && {
4436
+ y: y
4437
+ }, z != null && {
4438
+ z: z
4439
+ });
4497
4440
  }
4498
4441
  }
4499
4442
  return channels;
@@ -4542,7 +4485,7 @@ function parseBezierKeyframes(curves, startFrame, endFrame) {
4542
4485
  };
4543
4486
  if (i === 0) {
4544
4487
  keyframes.push(_extends({
4545
- t: frameTime,
4488
+ frame: frameTime,
4546
4489
  value: v0
4547
4490
  }, isHold ? {
4548
4491
  hold: true
@@ -4562,7 +4505,7 @@ function parseBezierKeyframes(curves, startFrame, endFrame) {
4562
4505
  y: inverseLerp(prevV0, prevV1, prevInCpY)
4563
4506
  };
4564
4507
  keyframes.push(_extends({
4565
- t: frameTime,
4508
+ frame: frameTime,
4566
4509
  value: v0,
4567
4510
  inTangent: inTangent
4568
4511
  }, isHold ? {
@@ -4581,7 +4524,7 @@ function parseBezierKeyframes(curves, startFrame, endFrame) {
4581
4524
  y: inverseLerp(lastSeg[1], lastSeg[7], lastSeg[5])
4582
4525
  };
4583
4526
  keyframes.push({
4584
- t: lastFrameTime,
4527
+ frame: lastFrameTime,
4585
4528
  value: lastV1,
4586
4529
  inTangent: lastInTangent
4587
4530
  });
@@ -4677,7 +4620,7 @@ function parsePositionTimingKeyframes(curves, startFrame, endFrame) {
4677
4620
  };
4678
4621
  if (i === 0) {
4679
4622
  result.push({
4680
- t: frameTime,
4623
+ frame: frameTime,
4681
4624
  outTangent: outTangent
4682
4625
  });
4683
4626
  } else {
@@ -4687,7 +4630,7 @@ function parsePositionTimingKeyframes(curves, startFrame, endFrame) {
4687
4630
  y: inverseLerp(prevSeg[0], prevSeg[6], prevSeg[5])
4688
4631
  };
4689
4632
  result.push({
4690
- t: frameTime,
4633
+ frame: frameTime,
4691
4634
  outTangent: outTangent,
4692
4635
  inTangent: inTangent
4693
4636
  });
@@ -4700,7 +4643,7 @@ function parsePositionTimingKeyframes(curves, startFrame, endFrame) {
4700
4643
  y: inverseLerp(lastSeg[0], lastSeg[6], lastSeg[5])
4701
4644
  };
4702
4645
  result.push({
4703
- t: lastFrameTime,
4646
+ frame: lastFrameTime,
4704
4647
  inTangent: lastInTangent
4705
4648
  });
4706
4649
  return result;
@@ -4717,12 +4660,9 @@ function parseTransformAnimation(asset, startFrame, endFrame, ctx) {
4717
4660
  }
4718
4661
  var rotOverLifetime = asset['rotationOverLifetime'];
4719
4662
  if (rotOverLifetime != null) {
4720
- var rotResult = parseRotationAnimation(rotOverLifetime, startFrame, endFrame);
4721
- if (rotResult.rotation != null) {
4722
- channels.rotation = rotResult.rotation;
4723
- }
4724
- if (rotResult.separatedRotation != null) {
4725
- channels.separatedRotation = rotResult.separatedRotation;
4663
+ var rotation = parseRotationAnimation(rotOverLifetime, startFrame, endFrame);
4664
+ if (rotation != null) {
4665
+ channels.rotation = rotation;
4726
4666
  }
4727
4667
  }
4728
4668
  var sizeOverLifetime = asset['sizeOverLifetime'];
@@ -4802,7 +4742,7 @@ function parsePositionAnimation(posOverLifetime, startFrame, endFrame, ctx) {
4802
4742
  var pp = pathPoints[Math.min(i, pathPoints.length - 1)];
4803
4743
  var pos2d = convert3dTo2dPoint(pp[0], pp[1], (_pp_ = pp[2]) != null ? _pp_ : 0, ctx.width, ctx.height);
4804
4744
  var kf = {
4805
- t: timing.t,
4745
+ frame: timing.frame,
4806
4746
  value: pos2d
4807
4747
  };
4808
4748
  if (i > startIdx && timing.inTangent != null) {
@@ -4851,83 +4791,26 @@ function parsePositionAnimation(posOverLifetime, startFrame, endFrame, ctx) {
4851
4791
  };
4852
4792
  }
4853
4793
  function parseRotationAnimation(rotOverLifetime, startFrame, endFrame) {
4854
- var separateAxes = rotOverLifetime['separateAxes'];
4794
+ var separateAxes = rotOverLifetime['separateAxes'] === true;
4855
4795
  var xData = rotOverLifetime['x'];
4856
4796
  var yData = rotOverLifetime['y'];
4857
4797
  var zData = rotOverLifetime['z'];
4858
- if (separateAxes === true) {
4859
- var x = parseScalarChannel(xData, startFrame, endFrame);
4860
- var y = parseScalarChannel(yData, startFrame, endFrame);
4861
- var z = parseScalarChannel(zData, startFrame, endFrame);
4862
- var hasMultiAxis = (x != null ? 1 : 0) + (y != null ? 1 : 0) + (z != null ? 1 : 0) > 1;
4863
- var hasXOrY = x != null || y != null;
4864
- if (hasMultiAxis || hasXOrY) {
4865
- return {
4866
- separatedRotation: _extends({}, x != null && {
4867
- x: x
4868
- }, y != null && {
4869
- y: y
4870
- }, z != null && {
4871
- z: z
4872
- })
4873
- };
4874
- }
4875
- if (z != null) {
4876
- return {
4877
- separatedRotation: {
4878
- z: z
4879
- }
4880
- };
4881
- }
4882
- }
4883
- // Single-axis z rotation (non-separated)
4884
- if (zData != null) {
4885
- var z1 = parseScalarChannel(zData, startFrame, endFrame);
4886
- if (z1 != null) {
4887
- if (z1.keyframed) {
4888
- var vecKeyframes = z1.keyframes.map(function(kf) {
4889
- var result = {
4890
- t: kf.t,
4891
- value: [
4892
- 0,
4893
- 0,
4894
- kf.value
4895
- ]
4896
- };
4897
- if (kf.hold != null) {
4898
- result.hold = kf.hold;
4899
- }
4900
- if (kf.inTangent != null) {
4901
- result.inTangent = kf.inTangent;
4902
- }
4903
- if (kf.outTangent != null) {
4904
- result.outTangent = kf.outTangent;
4905
- }
4906
- return result;
4907
- });
4908
- return {
4909
- rotation: {
4910
- keyframed: true,
4911
- keyframes: vecKeyframes
4912
- }
4913
- };
4914
- }
4915
- return {
4916
- rotation: {
4917
- keyframed: false,
4918
- value: [
4919
- 0,
4920
- 0,
4921
- z1.value
4922
- ]
4923
- }
4924
- };
4925
- }
4798
+ var x = separateAxes ? parseScalarChannel(xData, startFrame, endFrame) : undefined;
4799
+ var y = separateAxes ? parseScalarChannel(yData, startFrame, endFrame) : undefined;
4800
+ var z = parseScalarChannel(zData, startFrame, endFrame);
4801
+ if (x == null && y == null && z == null) {
4802
+ return undefined;
4926
4803
  }
4927
- return {};
4804
+ return _extends({}, x != null && {
4805
+ x: x
4806
+ }, y != null && {
4807
+ y: y
4808
+ }, z != null && {
4809
+ z: z
4810
+ });
4928
4811
  }
4929
4812
  function parseScaleAnimation(sizeOverLifetime, startFrame, endFrame) {
4930
- var _ref, _ref1, _ref2, _ref3, _ref4, _ref5, _ref6, _ref7, _ref8;
4813
+ var _ref, _ref1, _ref2;
4931
4814
  var xData = sizeOverLifetime['x'];
4932
4815
  var yData = sizeOverLifetime['y'];
4933
4816
  var zData = sizeOverLifetime['z'];
@@ -4940,71 +4823,72 @@ function parseScaleAnimation(sizeOverLifetime, startFrame, endFrame) {
4940
4823
  var xKeyframed = (x == null ? void 0 : x.keyframed) === true;
4941
4824
  var yKeyframed = (y == null ? void 0 : y.keyframed) === true;
4942
4825
  var zKeyframed = (z == null ? void 0 : z.keyframed) === true;
4826
+ var xStaticValue = (x == null ? void 0 : x.keyframed) === false ? x.value : 1;
4827
+ var yStaticValue = (y == null ? void 0 : y.keyframed) === false ? y.value : 1;
4828
+ var zStaticValue = (z == null ? void 0 : z.keyframed) === false ? z.value : 1;
4943
4829
  if (!xKeyframed && !yKeyframed && !zKeyframed) {
4944
- var _ref9, _ref10, _ref11;
4945
4830
  return {
4946
4831
  keyframed: false,
4947
4832
  value: [
4948
- (_ref9 = x == null ? void 0 : x.value) != null ? _ref9 : 1,
4949
- (_ref10 = y == null ? void 0 : y.value) != null ? _ref10 : 1,
4950
- (_ref11 = z == null ? void 0 : z.value) != null ? _ref11 : 1
4833
+ xStaticValue,
4834
+ yStaticValue,
4835
+ zStaticValue
4951
4836
  ]
4952
4837
  };
4953
4838
  }
4954
4839
  var xKfs = (_ref = x == null ? void 0 : x.keyframes) != null ? _ref : [
4955
4840
  {
4956
- t: startFrame,
4957
- value: (_ref1 = x == null ? void 0 : x.value) != null ? _ref1 : 1
4841
+ frame: startFrame,
4842
+ value: xStaticValue
4958
4843
  },
4959
4844
  {
4960
- t: endFrame,
4961
- value: (_ref2 = x == null ? void 0 : x.value) != null ? _ref2 : 1
4845
+ frame: endFrame,
4846
+ value: xStaticValue
4962
4847
  }
4963
4848
  ];
4964
- var yKfs = (_ref3 = y == null ? void 0 : y.keyframes) != null ? _ref3 : [
4849
+ var yKfs = (_ref1 = y == null ? void 0 : y.keyframes) != null ? _ref1 : [
4965
4850
  {
4966
- t: startFrame,
4967
- value: (_ref4 = y == null ? void 0 : y.value) != null ? _ref4 : 1
4851
+ frame: startFrame,
4852
+ value: yStaticValue
4968
4853
  },
4969
4854
  {
4970
- t: endFrame,
4971
- value: (_ref5 = y == null ? void 0 : y.value) != null ? _ref5 : 1
4855
+ frame: endFrame,
4856
+ value: yStaticValue
4972
4857
  }
4973
4858
  ];
4974
- var zKfs = (_ref6 = z == null ? void 0 : z.keyframes) != null ? _ref6 : [
4859
+ var zKfs = (_ref2 = z == null ? void 0 : z.keyframes) != null ? _ref2 : [
4975
4860
  {
4976
- t: startFrame,
4977
- value: (_ref7 = z == null ? void 0 : z.value) != null ? _ref7 : 1
4861
+ frame: startFrame,
4862
+ value: zStaticValue
4978
4863
  },
4979
4864
  {
4980
- t: endFrame,
4981
- value: (_ref8 = z == null ? void 0 : z.value) != null ? _ref8 : 1
4865
+ frame: endFrame,
4866
+ value: zStaticValue
4982
4867
  }
4983
4868
  ];
4984
- var allTimes = new Set();
4869
+ var allFrames = new Set();
4985
4870
  for(var _iterator = _create_for_of_iterator_helper_loose(xKfs), _step; !(_step = _iterator()).done;){
4986
4871
  var kf = _step.value;
4987
- allTimes.add(kf.t);
4872
+ allFrames.add(kf.frame);
4988
4873
  }
4989
4874
  for(var _iterator1 = _create_for_of_iterator_helper_loose(yKfs), _step1; !(_step1 = _iterator1()).done;){
4990
4875
  var kf1 = _step1.value;
4991
- allTimes.add(kf1.t);
4876
+ allFrames.add(kf1.frame);
4992
4877
  }
4993
4878
  for(var _iterator2 = _create_for_of_iterator_helper_loose(zKfs), _step2; !(_step2 = _iterator2()).done;){
4994
4879
  var kf2 = _step2.value;
4995
- allTimes.add(kf2.t);
4880
+ allFrames.add(kf2.frame);
4996
4881
  }
4997
4882
  // Keep Array.from: loose SWC array-spread lowering does not expand Set in dist.
4998
- var sortedTimes = Array.from(allTimes).sort(function(a, b) {
4883
+ var sortedFrames = Array.from(allFrames).sort(function(a, b) {
4999
4884
  return a - b;
5000
4885
  });
5001
- var keyframes = sortedTimes.map(function(t) {
5002
- var _ref, _ref1, _ref2;
5003
- var xv = findValueAtTime(xKfs, t, (_ref = x == null ? void 0 : x.value) != null ? _ref : 1);
5004
- var yv = findValueAtTime(yKfs, t, (_ref1 = y == null ? void 0 : y.value) != null ? _ref1 : 1);
5005
- var zv = findValueAtTime(zKfs, t, (_ref2 = z == null ? void 0 : z.value) != null ? _ref2 : 1);
4886
+ var keyframes = sortedFrames.map(function(frame) {
4887
+ var xv = findValueAtFrame(xKfs, frame, xStaticValue);
4888
+ var yv = findValueAtFrame(yKfs, frame, yStaticValue);
4889
+ var zv = findValueAtFrame(zKfs, frame, zStaticValue);
5006
4890
  var kf = {
5007
- t: t,
4891
+ frame: frame,
5008
4892
  value: [
5009
4893
  xv.value,
5010
4894
  yv.value,
@@ -5050,10 +4934,10 @@ function parseScalarChannel(data, startFrame, endFrame) {
5050
4934
  }
5051
4935
  return undefined;
5052
4936
  }
5053
- function findValueAtTime(keyframes, t, defaultValue) {
4937
+ function findValueAtFrame(keyframes, frame, defaultValue) {
5054
4938
  for(var _iterator = _create_for_of_iterator_helper_loose(keyframes), _step; !(_step = _iterator()).done;){
5055
4939
  var kf = _step.value;
5056
- if (Math.abs(kf.t - t) < 1e-6) {
4940
+ if (Math.abs(kf.frame - frame) < 1e-6) {
5057
4941
  return {
5058
4942
  value: kf.value,
5059
4943
  outTangent: kf.outTangent,
@@ -5085,11 +4969,11 @@ var IR_BLEND_MODE_BY_GE = {
5085
4969
  15: animationIr.IRBlendMode.SoftLight,
5086
4970
  16: animationIr.IRBlendMode.Luminosity
5087
4971
  };
5088
- function reverseBlendMode(geCode) {
5089
- if (geCode == null) {
4972
+ function reverseBlendMode(GECode) {
4973
+ if (GECode == null) {
5090
4974
  return undefined;
5091
4975
  }
5092
- return IR_BLEND_MODE_BY_GE[geCode];
4976
+ return IR_BLEND_MODE_BY_GE[GECode];
5093
4977
  }
5094
4978
 
5095
4979
  function parseComponent(item, ctx) {
@@ -5119,7 +5003,7 @@ function parseComponent(item, ctx) {
5119
5003
  if (result == null) {
5120
5004
  continue;
5121
5005
  }
5122
- result.geComponentId = component['id'];
5006
+ result.GEComponentId = component['id'];
5123
5007
  var mask = component['mask'];
5124
5008
  if (mask != null) {
5125
5009
  result.rawMask = mask;
@@ -5243,7 +5127,7 @@ function parseShapeComponent(component, ctx) {
5243
5127
  if (renderer != null) {
5244
5128
  blendMode = reverseBlendMode(renderer['blending']);
5245
5129
  }
5246
- var shapeData = parseShapeOptions(component, ctx.ratio);
5130
+ var shapeData = parseShapeOptions(component, ctx);
5247
5131
  return {
5248
5132
  type: 'shape',
5249
5133
  shapes: shapeData != null ? [
@@ -5252,85 +5136,100 @@ function parseShapeComponent(component, ctx) {
5252
5136
  blendMode: blendMode
5253
5137
  };
5254
5138
  }
5255
- function parseShapeOptions(component, ratio) {
5256
- var geType = component['type'];
5257
- var primitiveType = reverseShapePrimitiveType(geType != null ? geType : 0);
5258
- var xSize = component['xSize'];
5259
- var ySize = component['ySize'];
5260
- var size = [
5261
- xSize != null ? xSize / ratio : 0,
5262
- ySize != null ? ySize / ratio : 0
5263
- ];
5264
- var shape = {
5265
- primitiveType: primitiveType,
5139
+ function parseShapeOptions(component, ctx) {
5140
+ var GEType = component['type'];
5141
+ var primitiveType = reverseShapePrimitiveType(GEType != null ? GEType : 0);
5142
+ var style = {
5266
5143
  position: [
5267
5144
  0,
5268
5145
  0
5269
5146
  ],
5270
- size: size,
5271
5147
  fills: [],
5272
5148
  strokes: []
5273
5149
  };
5274
- var shapeRec = shape;
5275
- reverseScaledNumber(shapeRec, component, 'xRadius', ratio);
5276
- reverseScaledNumber(shapeRec, component, 'yRadius', ratio);
5277
- reverseScaledNumber(shapeRec, component, 'width', ratio);
5278
- reverseScaledNumber(shapeRec, component, 'height', ratio);
5279
- reverseScaledNumber(shapeRec, component, 'innerRadius', ratio);
5280
- reverseScaledNumber(shapeRec, component, 'outerRadius', ratio);
5281
- reverseScaledNumber(shapeRec, component, 'radius', ratio);
5282
- reverseRawNumber(shapeRec, component, 'roundness');
5283
- reverseRawNumber(shapeRec, component, 'pointCount');
5284
- reverseRawNumber(shapeRec, component, 'innerRoundness');
5285
- reverseRawNumber(shapeRec, component, 'outerRoundness');
5286
- var geFills = component['fills'];
5287
- if (geFills != null) {
5288
- shape.fills = geFills.map(function(f) {
5289
- return reverseShapePaint(f, ratio);
5150
+ var GEFills = component['fills'];
5151
+ if (GEFills != null) {
5152
+ style.fills = GEFills.map(function(f) {
5153
+ return reverseShapePaint(f, ctx);
5290
5154
  }).filter(function(f) {
5291
5155
  return f != null;
5292
5156
  });
5293
5157
  }
5294
- var geStrokes = component['strokes'];
5295
- if (geStrokes != null) {
5296
- shape.strokes = geStrokes.map(function(s) {
5297
- return reverseShapePaint(s, ratio);
5158
+ var GEStrokes = component['strokes'];
5159
+ if (GEStrokes != null) {
5160
+ style.strokes = GEStrokes.map(function(s) {
5161
+ return reverseShapePaint(s, ctx);
5298
5162
  }).filter(function(s) {
5299
5163
  return s != null;
5300
5164
  });
5301
5165
  }
5302
- var geStrokeWidth = component['strokeWidth'];
5303
- if (geStrokeWidth != null) {
5304
- shape.strokeWidth = geStrokeWidth / ratio;
5305
- }
5306
- var geStrokeCap = component['strokeCap'];
5307
- if (geStrokeCap != null) {
5308
- shape.strokeCap = reverseLineCap(geStrokeCap);
5166
+ var GEStrokeWidth = component['strokeWidth'];
5167
+ if (typeof GEStrokeWidth === 'number' && Number.isFinite(GEStrokeWidth) && GEStrokeWidth >= 0) {
5168
+ style.strokeWidth = GEStrokeWidth / ctx.ratio;
5309
5169
  }
5310
- var geStrokeJoin = component['strokeJoin'];
5311
- if (geStrokeJoin != null) {
5312
- shape.strokeJoin = reverseLineJoin(geStrokeJoin);
5170
+ var GEStrokeCap = component['strokeCap'];
5171
+ if (GEStrokeCap != null) {
5172
+ style.strokeCap = reverseLineCap(GEStrokeCap);
5313
5173
  }
5314
- var geFillRule = component['fillRule'];
5315
- if (geFillRule != null) {
5316
- shape.fillRule = reverseShapeFillRule(geFillRule);
5174
+ var GEStrokeJoin = component['strokeJoin'];
5175
+ if (GEStrokeJoin != null) {
5176
+ style.strokeJoin = reverseLineJoin(GEStrokeJoin);
5317
5177
  }
5318
- var geShapes = component['shapes'];
5319
- if (geShapes != null) {
5320
- var paths = reverseCustomPaths(component, ratio);
5321
- if (paths.length > 0) {
5322
- shape.customPaths = paths;
5323
- }
5324
- }
5325
- var trimPath = component['trimPath'];
5326
- if (trimPath != null) {
5327
- shape.trimPath = trimPath;
5328
- }
5329
- var repeater = component['repeater'];
5330
- if (repeater != null) {
5331
- shape.repeater = repeater;
5178
+ switch(primitiveType){
5179
+ case animationIr.IRShapePrimitiveType.Custom:
5180
+ {
5181
+ var customPaths = reverseCustomPaths(component, ctx.ratio);
5182
+ var firstPath = customPaths[0];
5183
+ return firstPath != null ? _extends({}, style, {
5184
+ primitiveType: primitiveType,
5185
+ customPaths: [].concat([
5186
+ firstPath
5187
+ ], customPaths.slice(1))
5188
+ }) : undefined;
5189
+ }
5190
+ case animationIr.IRShapePrimitiveType.Rectangle:
5191
+ {
5192
+ var width = readScaledNumber(component, 'width', ctx.ratio);
5193
+ var height = readScaledNumber(component, 'height', ctx.ratio);
5194
+ return width != null && height != null ? _extends({}, style, {
5195
+ primitiveType: primitiveType,
5196
+ width: width,
5197
+ height: height
5198
+ }, readOptionalNumberField(component, 'roundness')) : undefined;
5199
+ }
5200
+ case animationIr.IRShapePrimitiveType.Ellipse:
5201
+ {
5202
+ var xRadius = readScaledNumber(component, 'xRadius', ctx.ratio);
5203
+ var yRadius = readScaledNumber(component, 'yRadius', ctx.ratio);
5204
+ return xRadius != null && yRadius != null ? _extends({}, style, {
5205
+ primitiveType: primitiveType,
5206
+ xRadius: xRadius,
5207
+ yRadius: yRadius
5208
+ }) : undefined;
5209
+ }
5210
+ case animationIr.IRShapePrimitiveType.Polygon:
5211
+ {
5212
+ var pointCount = readPointCount(component);
5213
+ var radius = readScaledNumber(component, 'radius', ctx.ratio);
5214
+ return pointCount != null && radius != null ? _extends({}, style, {
5215
+ primitiveType: primitiveType,
5216
+ pointCount: pointCount,
5217
+ radius: radius
5218
+ }, readOptionalNumberField(component, 'roundness')) : undefined;
5219
+ }
5220
+ case animationIr.IRShapePrimitiveType.Star:
5221
+ {
5222
+ var pointCount1 = readPointCount(component);
5223
+ var innerRadius = readScaledNumber(component, 'innerRadius', ctx.ratio);
5224
+ var outerRadius = readScaledNumber(component, 'outerRadius', ctx.ratio);
5225
+ return pointCount1 != null && innerRadius != null && outerRadius != null ? _extends({}, style, {
5226
+ primitiveType: primitiveType,
5227
+ pointCount: pointCount1,
5228
+ innerRadius: innerRadius,
5229
+ outerRadius: outerRadius
5230
+ }, readOptionalNumberField(component, 'innerRoundness'), readOptionalNumberField(component, 'outerRoundness')) : undefined;
5231
+ }
5332
5232
  }
5333
- return shape;
5334
5233
  }
5335
5234
  var GE_TO_SHAPE_PRIMITIVE_TYPE = {
5336
5235
  0: animationIr.IRShapePrimitiveType.Custom,
@@ -5339,13 +5238,13 @@ var GE_TO_SHAPE_PRIMITIVE_TYPE = {
5339
5238
  3: animationIr.IRShapePrimitiveType.Polygon,
5340
5239
  4: animationIr.IRShapePrimitiveType.Star
5341
5240
  };
5342
- function reverseShapePrimitiveType(geType) {
5343
- var _GE_TO_SHAPE_PRIMITIVE_TYPE_geType;
5344
- return (_GE_TO_SHAPE_PRIMITIVE_TYPE_geType = GE_TO_SHAPE_PRIMITIVE_TYPE[geType]) != null ? _GE_TO_SHAPE_PRIMITIVE_TYPE_geType : animationIr.IRShapePrimitiveType.Custom;
5241
+ function reverseShapePrimitiveType(GEType) {
5242
+ var _GE_TO_SHAPE_PRIMITIVE_TYPE_GEType;
5243
+ return (_GE_TO_SHAPE_PRIMITIVE_TYPE_GEType = GE_TO_SHAPE_PRIMITIVE_TYPE[GEType]) != null ? _GE_TO_SHAPE_PRIMITIVE_TYPE_GEType : animationIr.IRShapePrimitiveType.Custom;
5345
5244
  }
5346
- function reverseShapePaint(paint, ratio) {
5347
- var geType = paint['type'];
5348
- if (geType === 0) {
5245
+ function reverseShapePaint(paint, ctx) {
5246
+ var GEType = paint['type'];
5247
+ if (GEType === 0) {
5349
5248
  var color = paint['color'];
5350
5249
  if (color == null) {
5351
5250
  return undefined;
@@ -5360,7 +5259,7 @@ function reverseShapePaint(paint, ratio) {
5360
5259
  ]
5361
5260
  };
5362
5261
  }
5363
- if (geType === 1 || geType === 2 || geType === 3) {
5262
+ if (GEType === 1 || GEType === 2 || GEType === 3) {
5364
5263
  var typeMap = {
5365
5264
  1: animationIr.IRFillType.LinearGradient,
5366
5265
  2: animationIr.IRFillType.RadialGradient,
@@ -5371,45 +5270,50 @@ function reverseShapePaint(paint, ratio) {
5371
5270
  var startPoint = paint['startPoint'];
5372
5271
  var endPoint = paint['endPoint'];
5373
5272
  return {
5374
- type: typeMap[geType],
5273
+ type: typeMap[GEType],
5375
5274
  gradientStops: stops,
5376
5275
  gradientStart: startPoint != null ? [
5377
- startPoint.x / ratio,
5378
- -startPoint.y / ratio
5276
+ startPoint.x / ctx.ratio,
5277
+ -startPoint.y / ctx.ratio
5379
5278
  ] : undefined,
5380
5279
  gradientEnd: endPoint != null ? [
5381
- endPoint.x / ratio,
5382
- -endPoint.y / ratio
5280
+ endPoint.x / ctx.ratio,
5281
+ -endPoint.y / ctx.ratio
5383
5282
  ] : undefined
5384
5283
  };
5385
5284
  }
5285
+ if (GEType === 4) {
5286
+ var texture = resolveTextureAsset(paint['texture'], ctx);
5287
+ if (texture == null) {
5288
+ return undefined;
5289
+ }
5290
+ var scaleMode = paint['scaleMode'];
5291
+ return _extends({
5292
+ type: animationIr.IRFillType.Texture,
5293
+ texture: texture
5294
+ }, isTextureScaleMode(scaleMode) && {
5295
+ scaleMode: scaleMode
5296
+ });
5297
+ }
5386
5298
  return undefined;
5387
5299
  }
5388
- function reverseLineCap(geCode) {
5389
- var _map_geCode;
5300
+ function reverseLineCap(GECode) {
5301
+ var _map_GECode;
5390
5302
  var map = {
5391
5303
  0: animationIr.IRLineCap.Butt,
5392
5304
  1: animationIr.IRLineCap.Round,
5393
5305
  2: animationIr.IRLineCap.Square
5394
5306
  };
5395
- return (_map_geCode = map[geCode]) != null ? _map_geCode : animationIr.IRLineCap.Butt;
5307
+ return (_map_GECode = map[GECode]) != null ? _map_GECode : animationIr.IRLineCap.Butt;
5396
5308
  }
5397
- function reverseLineJoin(geCode) {
5398
- var _map_geCode;
5309
+ function reverseLineJoin(GECode) {
5310
+ var _map_GECode;
5399
5311
  var map = {
5400
5312
  0: animationIr.IRLineJoin.Round,
5401
5313
  1: animationIr.IRLineJoin.Bevel,
5402
5314
  2: animationIr.IRLineJoin.Miter
5403
5315
  };
5404
- return (_map_geCode = map[geCode]) != null ? _map_geCode : animationIr.IRLineJoin.Miter;
5405
- }
5406
- function reverseShapeFillRule(geCode) {
5407
- var _map_geCode;
5408
- var map = {
5409
- 0: animationIr.IRShapeFillRule.NonZero,
5410
- 1: animationIr.IRShapeFillRule.EvenOdd
5411
- };
5412
- return (_map_geCode = map[geCode]) != null ? _map_geCode : animationIr.IRShapeFillRule.NonZero;
5316
+ return (_map_GECode = map[GECode]) != null ? _map_GECode : animationIr.IRLineJoin.Miter;
5413
5317
  }
5414
5318
  function reverseCustomPaths(component, ratio) {
5415
5319
  var points = component['points'];
@@ -5421,8 +5325,8 @@ function reverseCustomPaths(component, ratio) {
5421
5325
  }
5422
5326
  return shapes.map(function(shape) {
5423
5327
  var pathPoints = [];
5424
- var pathEasingIns = [];
5425
- var pathEasingOuts = [];
5328
+ var pathInTangents = [];
5329
+ var pathOutTangents = [];
5426
5330
  for(var _iterator = _create_for_of_iterator_helper_loose(shape.indexes), _step; !(_step = _iterator()).done;){
5427
5331
  var idx = _step.value;
5428
5332
  var _ref, _ref1, _ref2, _ref3;
@@ -5433,34 +5337,50 @@ function reverseCustomPaths(component, ratio) {
5433
5337
  x: pt.x / ratio,
5434
5338
  y: -pt.y / ratio
5435
5339
  });
5436
- pathEasingIns.push({
5340
+ pathInTangents.push({
5437
5341
  x: ((_ref = ei == null ? void 0 : ei.x) != null ? _ref : 0) / ratio,
5438
5342
  y: -((_ref1 = ei == null ? void 0 : ei.y) != null ? _ref1 : 0) / ratio
5439
5343
  });
5440
- pathEasingOuts.push({
5344
+ pathOutTangents.push({
5441
5345
  x: ((_ref2 = eo == null ? void 0 : eo.x) != null ? _ref2 : 0) / ratio,
5442
5346
  y: -((_ref3 = eo == null ? void 0 : eo.y) != null ? _ref3 : 0) / ratio
5443
5347
  });
5444
5348
  }
5445
5349
  return {
5446
5350
  points: pathPoints,
5447
- easingIns: pathEasingIns,
5448
- easingOuts: pathEasingOuts,
5449
- close: shape.close
5351
+ inTangents: pathInTangents,
5352
+ outTangents: pathOutTangents,
5353
+ closed: shape.close
5450
5354
  };
5451
5355
  });
5452
5356
  }
5453
- function reverseScaledNumber(shape, component, key, ratio) {
5357
+ function readScaledNumber(component, key, ratio) {
5454
5358
  var value = component[key];
5455
- if (typeof value === 'number') {
5456
- shape[key] = value / ratio;
5359
+ if (typeof value !== 'number' || !Number.isFinite(value) || value < 0) {
5360
+ return undefined;
5457
5361
  }
5362
+ return value / ratio;
5458
5363
  }
5459
- function reverseRawNumber(shape, component, key) {
5364
+ function readOptionalNumberField(component, key) {
5460
5365
  var value = component[key];
5461
- if (typeof value === 'number') {
5462
- shape[key] = value;
5463
- }
5366
+ var _obj;
5367
+ return typeof value === 'number' && Number.isFinite(value) ? (_obj = {}, _obj[key] = value, _obj) : {};
5368
+ }
5369
+ function readPointCount(component) {
5370
+ var value = component['pointCount'];
5371
+ return typeof value === 'number' && Number.isInteger(value) && value >= 2 ? value : undefined;
5372
+ }
5373
+ function resolveTextureAsset(textureRef, ctx) {
5374
+ var texture = resolveDataPath(ctx.textureById, textureRef);
5375
+ var sourceRef = texture == null ? void 0 : texture['source'];
5376
+ var image = sourceRef != null ? resolveDataPath(ctx.imageById, sourceRef) : undefined;
5377
+ var url = image == null ? void 0 : image['url'];
5378
+ return typeof url === 'string' && url.trim() !== '' ? {
5379
+ url: url
5380
+ } : undefined;
5381
+ }
5382
+ function isTextureScaleMode(value) {
5383
+ return typeof value === 'number' && Number.isInteger(value) && value >= 0 && value <= 3;
5464
5384
  }
5465
5385
 
5466
5386
  function reverseLayerTiming(delay, duration, frameRate) {
@@ -5501,7 +5421,7 @@ function mergeNullSpritePairs(descriptors, ctx) {
5501
5421
  // child is exactly one same-name visual sprite. ir2ge's emitNullSpritePair
5502
5422
  // produces precisely this shape (null + one same-name child). If the null
5503
5423
  // has any OTHER children, it is a genuine Lottie parent null — merging it
5504
- // into a transformSplit would change the anchor those other children are
5424
+ // into a single semantic layer would change the anchor those other children are
5505
5425
  // parented against, shifting them. Leave such nulls intact.
5506
5426
  if (children.length !== 1) {
5507
5427
  continue;
@@ -5615,19 +5535,17 @@ function isRecord$1(value) {
5615
5535
  return value != null && (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object' && !Array.isArray(value);
5616
5536
  }
5617
5537
  function mergeNullAndSprite(nullDesc, childDesc, ctx) {
5618
- var _childDesc_layer_transform;
5538
+ var _childDesc_layer_transform, _merged_specific;
5619
5539
  var merged = _extends({}, nullDesc.layer);
5620
5540
  // Take type from child
5621
5541
  merged.type = childDesc.layer.type;
5622
5542
  merged.asset = childDesc.layer.asset;
5623
5543
  merged.text = childDesc.layer.text;
5624
5544
  merged.shapes = childDesc.layer.shapes;
5625
- merged.shapeLayer = childDesc.layer.shapeLayer;
5626
5545
  merged.solidColor = childDesc.layer.solidColor;
5627
5546
  merged.blendMode = childDesc.layer.blendMode;
5628
- merged.transformSplit = true;
5629
5547
  // Visibility from child
5630
- merged.visibility = childDesc.layer.visibility;
5548
+ merged.visible = childDesc.layer.visible;
5631
5549
  // Compute anchor from child position offset
5632
5550
  var childTransform = childDesc.item['transform'];
5633
5551
  var childPosition = childTransform == null ? void 0 : childTransform['position'];
@@ -5648,7 +5566,9 @@ function mergeNullAndSprite(nullDesc, childDesc, ctx) {
5648
5566
  0
5649
5567
  ]
5650
5568
  };
5651
- merged.displaySize = {
5569
+ merged.localBounds = {
5570
+ x: 0,
5571
+ y: 0,
5652
5572
  width: layerWidth,
5653
5573
  height: layerHeight
5654
5574
  };
@@ -5661,17 +5581,21 @@ function mergeNullAndSprite(nullDesc, childDesc, ctx) {
5661
5581
  merged.transform.opacity = childDesc.layer.transform.opacity;
5662
5582
  }
5663
5583
  // The merged layer renders the child's visual component, but the parent owns
5664
- // transform animation passthrough. Deep-merge the ge2ir namespace so neither
5665
- // side overwrites the other's GE round-trip data.
5666
- if (childDesc.layer.metadata != null) {
5667
- var _merged_metadata;
5668
- var parentGE2IR = isRecord$1((_merged_metadata = merged.metadata) == null ? void 0 : _merged_metadata['ge2ir']) ? merged.metadata['ge2ir'] : undefined;
5669
- var childGE2IR = isRecord$1(childDesc.layer.metadata['ge2ir']) ? childDesc.layer.metadata['ge2ir'] : undefined;
5670
- merged.metadata = _extends({}, merged.metadata, childDesc.layer.metadata);
5671
- if (parentGE2IR != null || childGE2IR != null) {
5672
- merged.metadata['ge2ir'] = _extends({}, parentGE2IR != null ? parentGE2IR : {}, childGE2IR != null ? childGE2IR : {});
5673
- }
5584
+ // transform animation passthrough. Deep-merge specific.effects so neither side
5585
+ // loses GE reconstruction data.
5586
+ if (childDesc.layer.specific != null) {
5587
+ var _merged_specific1;
5588
+ var parentEffects = (_merged_specific1 = merged.specific) == null ? void 0 : _merged_specific1.effects;
5589
+ var childEffects = childDesc.layer.specific.effects;
5590
+ merged.specific = _extends({}, merged.specific, childDesc.layer.specific, (parentEffects != null || childEffects != null) && {
5591
+ effects: _extends({}, parentEffects != null ? parentEffects : {}, childEffects != null ? childEffects : {})
5592
+ });
5674
5593
  }
5594
+ merged.specific = _extends({}, merged.specific, {
5595
+ effects: _extends({}, (_merged_specific = merged.specific) == null ? void 0 : _merged_specific.effects, {
5596
+ sourceHierarchy: 'null-sprite-pair'
5597
+ })
5598
+ });
5675
5599
  return {
5676
5600
  itemId: nullDesc.itemId,
5677
5601
  item: nullDesc.item,
@@ -5700,7 +5624,7 @@ function resolveHierarchy(descriptors, ctx) {
5700
5624
  }
5701
5625
  desc1.layer.parent = {
5702
5626
  index: parentIndex,
5703
- name: parentDesc.layer.name
5627
+ lifetimeMode: 'clipped'
5704
5628
  };
5705
5629
  var parentAnchor = getAnchorFromDesc(parentDesc);
5706
5630
  var pos = (_desc_layer_transform = desc1.layer.transform) == null ? void 0 : _desc_layer_transform.position;
@@ -5765,7 +5689,7 @@ function convertGEToIR(scene, options) {
5765
5689
  return d.layer;
5766
5690
  });
5767
5691
  return normalizeJsonValue({
5768
- source: 'ge',
5692
+ source: 'effects',
5769
5693
  name: ctx.compositionName,
5770
5694
  width: ctx.width,
5771
5695
  height: ctx.height,
@@ -5775,14 +5699,13 @@ function convertGEToIR(scene, options) {
5775
5699
  backgroundColor: ctx.backgroundColor,
5776
5700
  endBehavior: ctx.endBehavior,
5777
5701
  layers: layers,
5778
- metadata: buildCompositionMetadata(scene, ctx.compositionId, itemIds, ctx)
5702
+ specific: buildCompositionSpecific(scene, ctx.compositionId, itemIds, ctx)
5779
5703
  });
5780
5704
  }
5781
5705
  function parseItemToLayer(item, itemId, index, ctx) {
5782
- var _item_name, _item_visible, _ref, _item_delay, _ref1, _item_duration;
5783
- var _item_transform;
5706
+ var _item_name, _item_visible, _ref, _item_delay, _ref1, _item_duration, _ref2;
5784
5707
  var name = (_item_name = item['name']) != null ? _item_name : "layer_" + index;
5785
- var geType = item['type'];
5708
+ var GEType = item['type'];
5786
5709
  var visible = (_item_visible = item['visible']) != null ? _item_visible : true;
5787
5710
  var rawTransformPassthrough;
5788
5711
  var timeline = parseTimeline(itemId, ctx);
@@ -5791,42 +5714,50 @@ function parseItemToLayer(item, itemId, index, ctx) {
5791
5714
  var time = reverseLayerTiming(delay, duration, ctx.frameRate);
5792
5715
  var componentData = parseComponent(item, ctx);
5793
5716
  var type;
5794
- if (geType === '3') {
5717
+ if (GEType === '3') {
5795
5718
  type = 'null';
5796
- } else if ((componentData == null ? void 0 : componentData.type) === 'text' || geType === 'text') {
5719
+ } else if ((componentData == null ? void 0 : componentData.type) === 'text' || GEType === 'text') {
5797
5720
  type = 'text';
5798
- } else if ((componentData == null ? void 0 : componentData.type) === 'shape' || geType === 'shape') {
5721
+ } else if ((componentData == null ? void 0 : componentData.type) === 'shape' || GEType === 'shape') {
5799
5722
  type = 'shape';
5800
5723
  } else if ((componentData == null ? void 0 : componentData.type) === 'image') {
5801
5724
  type = 'image';
5802
- } else if (geType === '7') {
5725
+ } else if (GEType === '7') {
5803
5726
  type = 'precomp';
5804
5727
  } else if ((componentData == null ? void 0 : componentData.solidColor) != null) {
5805
5728
  type = 'solid';
5806
- } else if (geType === '1') {
5729
+ } else if (GEType === '1') {
5807
5730
  type = 'solid';
5808
5731
  } else {
5809
5732
  type = 'null';
5810
5733
  }
5811
5734
  // Parse transforms
5812
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;
5813
5744
  var transform;
5814
5745
  if (itemTransform != null) {
5815
5746
  var staticChannels = parseStaticTransform(itemTransform, ctx);
5816
5747
  transform = _extends({}, staticChannels);
5817
5748
  // Text layers carry their pixel-sizing scale on transform.scale
5818
- // (scale = ratio × displaySize). ir2ge RECOMPUTES this item scale from
5819
- // displaySize in processVisualLayer, so keeping it in the IR scale channel
5749
+ // (scale = ratio × local bounds). ir2ge RECOMPUTES this item scale from
5750
+ // localBounds in processVisualLayer, so keeping it in the IR scale channel
5820
5751
  // would make buildSizeAnim emit a duplicate sizeOverLifetime constant that
5821
5752
  // double-scales the glyphs (garbled/stretched text). Drop the static scale
5822
5753
  // for text; genuine text scale animation still rides through
5823
- // metadata.ge2ir.sizeOverLifetime passthrough.
5754
+ // specific.effects.sizeOverLifetime passthrough.
5824
5755
  if (type === 'text') {
5825
5756
  delete transform.scale;
5826
5757
  }
5827
5758
  }
5828
5759
  // Parse animation from timeline tracks — passthrough raw GE animation data
5829
- // via metadata. Converting to IR keyframes and back would lose data (ir2ge
5760
+ // via specific.effects. Converting to IR keyframes and back would lose data (ir2ge
5830
5761
  // only handles specific ValueType variants and makes assumptions about
5831
5762
  // static positions). The raw data is injected verbatim by ir2ge.
5832
5763
  if ((timeline == null ? void 0 : timeline.transformAsset) != null) {
@@ -5840,10 +5771,6 @@ function parseItemToLayer(item, itemId, index, ctx) {
5840
5771
  if (animChannels.rotation != null) {
5841
5772
  transform.rotation = animChannels.rotation;
5842
5773
  }
5843
- if (animChannels.separatedRotation != null) {
5844
- transform.separatedRotation = animChannels.separatedRotation;
5845
- delete transform.rotation;
5846
- }
5847
5774
  if (animChannels.scale != null) {
5848
5775
  transform.scale = animChannels.scale;
5849
5776
  }
@@ -5880,108 +5807,104 @@ function parseItemToLayer(item, itemId, index, ctx) {
5880
5807
  rawColorOverLifetime = col;
5881
5808
  }
5882
5809
  }
5883
- // Anchor from component — default to center (0.5, 0.5) when not explicitly set
5884
- if (type !== 'null') {
5885
- var _item_transform1;
5886
- var itemSize = (_item_transform1 = item['transform']) == null ? void 0 : _item_transform1['size'];
5887
- if (itemSize != null) {
5888
- var _ref2;
5889
- var layerWidth = itemSize.x / ctx.ratio;
5890
- var layerHeight = itemSize.y / ctx.ratio;
5891
- var anchorScale = (_ref2 = componentData == null ? void 0 : componentData.anchorScale) != null ? _ref2 : [
5892
- 0.5,
5893
- 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
5894
5851
  ];
5895
- var anchorX = anchorScale[0] * layerWidth;
5896
- var anchorY = anchorScale[1] * layerHeight;
5897
- if (transform == null) {
5898
- 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);
5899
5863
  }
5900
- transform.anchor = {
5901
- keyframed: false,
5902
- value: [
5903
- anchorX,
5904
- anchorY,
5905
- 0
5906
- ]
5907
- };
5908
- // Reverse the position adjustments ir2ge's processVisualLayer re-applies
5909
- // for non-centered anchors, so they don't double-apply on round-trip.
5910
- // Forward order (in 2D-px equivalent): pos += anchorOffset (computeStaticPosition),
5911
- // then pos += scaleAdjust (applyScalePositionAdjust). We subtract both.
5912
- var pos = transform.position;
5913
- if (pos != null && !pos.keyframed && pos.value != null) {
5914
- var _scale_, _scale_1;
5915
- var _transform_scale;
5916
- // anchorOffset = -(anchor - size/2), added to the raw 2D position.
5917
- var anchorOffsetX = -(anchorX - layerWidth / 2);
5918
- var anchorOffsetY = -(anchorY - layerHeight / 2);
5919
- // scaleAdjust (only when static scale != 1 and anchor off-center by >0.5px):
5920
- // 3D: x += anchorDiffX*(1-sx)*ratio ; y -= anchorDiffY*(1-sy)*ratio
5921
- // In 2D-px (÷ratio, y-axis flips sign): x2d += anchorDiffX*(1-sx) ;
5922
- // y2d += anchorDiffY*(1-sy) (the two sign flips cancel).
5923
- var scale = ((_transform_scale = transform.scale) == null ? void 0 : _transform_scale.keyframed) === false && Array.isArray(transform.scale.value) ? transform.scale.value : [
5924
- 1,
5925
- 1,
5926
- 1
5927
- ];
5928
- var sx = (_scale_ = scale[0]) != null ? _scale_ : 1;
5929
- var sy = (_scale_1 = scale[1]) != null ? _scale_1 : 1;
5930
- var anchorDiffX = anchorX - layerWidth / 2;
5931
- var anchorDiffY = anchorY - layerHeight / 2;
5932
- var anchorOffCenter = Math.abs(anchorDiffX) > 0.5 || Math.abs(anchorDiffY) > 0.5;
5933
- var hasStaticScale = !(sx === 1 && sy === 1);
5934
- var scaleAdjustX = 0;
5935
- var scaleAdjustY = 0;
5936
- if (hasStaticScale && anchorOffCenter && layerWidth > 0 && layerHeight > 0) {
5937
- scaleAdjustX = anchorDiffX * (1 - sx);
5938
- scaleAdjustY = anchorDiffY * (1 - sy);
5939
- }
5940
- var totalX = anchorOffsetX + scaleAdjustX;
5941
- var totalY = anchorOffsetY + scaleAdjustY;
5942
- if (Math.abs(totalX) > 1e-6 || Math.abs(totalY) > 1e-6) {
5943
- var _pos_value_;
5944
- transform.position = {
5945
- keyframed: false,
5946
- value: [
5947
- pos.value[0] - totalX,
5948
- pos.value[1] - totalY,
5949
- (_pos_value_ = pos.value[2]) != null ? _pos_value_ : 0
5950
- ]
5951
- };
5952
- }
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
+ };
5953
5876
  }
5954
5877
  }
5955
5878
  }
5956
- // Display size from item transform.size
5957
- var displaySize;
5958
- var itemSize1 = (_item_transform = item['transform']) == null ? void 0 : _item_transform['size'];
5959
- if (itemSize1 != null) {
5960
- displaySize = {
5961
- width: itemSize1.x / ctx.ratio,
5962
- height: itemSize1.y / ctx.ratio
5963
- };
5879
+ var text = (componentData == null ? void 0 : componentData.text) == null ? undefined : _extends({}, componentData.text);
5880
+ var solidColor = type === 'solid' ? (_ref2 = componentData == null ? void 0 : componentData.solidColor) != null ? _ref2 : [
5881
+ 1,
5882
+ 1,
5883
+ 1,
5884
+ 1
5885
+ ] : componentData == null ? void 0 : componentData.solidColor;
5886
+ if ((text == null ? void 0 : text.autoWidth) === false) {
5887
+ var _text, _width, _text1, _height;
5888
+ (_width = (_text = text).width) != null ? _width : _text.width = localBounds == null ? void 0 : localBounds.width;
5889
+ (_height = (_text1 = text).height) != null ? _height : _text1.height = localBounds == null ? void 0 : localBounds.height;
5964
5890
  }
5965
5891
  var layer = {
5966
5892
  index: index,
5967
5893
  name: name,
5968
5894
  type: type,
5969
5895
  time: time,
5970
- visibility: {
5971
- hidden: !visible,
5972
- enabled: visible
5973
- },
5896
+ visible: visible,
5974
5897
  transform: transform,
5975
- displaySize: displaySize
5898
+ localBounds: localBounds
5976
5899
  };
5977
5900
  if ((componentData == null ? void 0 : componentData.asset) != null) {
5978
5901
  layer.asset = componentData.asset;
5979
5902
  }
5980
- if ((componentData == null ? void 0 : componentData.solidColor) != null) {
5981
- layer.solidColor = componentData.solidColor;
5903
+ if (solidColor != null) {
5904
+ layer.solidColor = solidColor;
5982
5905
  }
5983
- if ((componentData == null ? void 0 : componentData.text) != null) {
5984
- layer.text = componentData.text;
5906
+ if (text != null) {
5907
+ layer.text = text;
5985
5908
  }
5986
5909
  if ((componentData == null ? void 0 : componentData.shapes) != null) {
5987
5910
  layer.shapes = componentData.shapes;
@@ -5989,38 +5912,39 @@ function parseItemToLayer(item, itemId, index, ctx) {
5989
5912
  if ((componentData == null ? void 0 : componentData.blendMode) != null) {
5990
5913
  layer.blendMode = componentData.blendMode;
5991
5914
  }
5992
- var geComponentId = componentData == null ? void 0 : componentData.geComponentId;
5915
+ var GEComponentId = componentData == null ? void 0 : componentData.GEComponentId;
5993
5916
  var rawMask = componentData == null ? void 0 : componentData.rawMask;
5994
- var precompContent = geType === '7' ? item['content'] : undefined;
5917
+ var precompContent = GEType === '7' ? item['content'] : undefined;
5995
5918
  var precompRefId = isRecord(precompContent == null ? void 0 : precompContent['options']) ? precompContent['options']['refId'] : undefined;
5996
- if (rawTransformPassthrough != null || rawColorOverLifetime != null || geComponentId != null || rawMask != null || typeof precompRefId === 'string' || precompContent != null) {
5997
- // Mask round-trip: geComponentId is the rendezvous key linking a target's
5998
- // mask.reference.id (a GE1 component id) to the regenerated GE2 component id.
5999
- // ir2ge copies ge2ir.geMask onto the rebuilt component and a post-process pass
6000
- // remaps the stale reference id.
6001
- var ge2irMetadata = _extends({}, rawTransformPassthrough != null ? rawTransformPassthrough : {}, rawColorOverLifetime != null && {
6002
- colorOverLifetime: rawColorOverLifetime
6003
- }, geComponentId != null && {
6004
- geComponentId: geComponentId
6005
- }, rawMask != null && {
6006
- geMask: rawMask
6007
- }, typeof precompRefId === 'string' && {
6008
- precompRefId: precompRefId
6009
- }, precompContent != null && {
6010
- precompContent: cloneJson(precompContent)
6011
- });
6012
- layer.metadata = _extends({}, layer.metadata, {
6013
- ge2ir: ge2irMetadata
6014
- });
6015
- }
5919
+ // Mask round-trip: GEComponentId is the rendezvous key linking a target's
5920
+ // mask.reference.id (a GE1 component id) to the regenerated GE2 component id.
5921
+ // ir2ge copies specific.effects.mask onto the rebuilt component and a post-process pass
5922
+ // remaps the stale reference id. sourceHierarchy records the pre-merge shape;
5923
+ // mergeNullSpritePairs replaces it when a pair collapses into one semantic layer.
5924
+ var effectsSpecific = _extends({
5925
+ sourceHierarchy: 'single-item'
5926
+ }, rawTransformPassthrough != null ? rawTransformPassthrough : {}, rawColorOverLifetime != null && {
5927
+ colorOverLifetime: rawColorOverLifetime
5928
+ }, GEComponentId != null && {
5929
+ sourceComponentId: GEComponentId
5930
+ }, rawMask != null && {
5931
+ mask: rawMask
5932
+ }, typeof precompRefId === 'string' && {
5933
+ precompRefId: precompRefId
5934
+ }, precompContent != null && {
5935
+ precompContent: cloneJson(precompContent)
5936
+ });
5937
+ layer.specific = _extends({}, layer.specific, {
5938
+ effects: effectsSpecific
5939
+ });
6016
5940
  return layer;
6017
5941
  }
6018
- function buildCompositionMetadata(scene, compositionId, itemIds, ctx) {
5942
+ function buildCompositionSpecific(scene, compositionId, itemIds, ctx) {
6019
5943
  if (!hasPrecompItem(itemIds, ctx)) {
6020
5944
  return undefined;
6021
5945
  }
6022
5946
  return {
6023
- ge2ir: {
5947
+ effects: {
6024
5948
  sourceCompositionId: compositionId,
6025
5949
  sourceScene: cloneJson(scene)
6026
5950
  }
@@ -6038,17 +5962,47 @@ function cloneJson(value) {
6038
5962
  function isRecord(value) {
6039
5963
  return value != null && (typeof value === "undefined" ? "undefined" : _type_of(value)) === 'object' && !Array.isArray(value);
6040
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
+ }
6041
5997
 
6042
5998
  /**
6043
5999
  * Read-side accessors for the `IRLayerNode.specific.lottie` slot.
6044
6000
  *
6045
6001
  * The shared generator must not branch on lottie semantics directly — every
6046
- * lottie-specific read goes through these helpers so the rest of `ir2ge` stays
6002
+ * Lottie-specific reads go through these helpers so the rest of ir2ge stays
6047
6003
  * agnostic to the producing tool.
6048
6004
  *
6049
- * `isTransformOnlyParentLink` used to live here, reading
6050
- * `specific.lottie.explicitParent`. It was promoted to a generic IR field
6051
- * (`IRLayerReference.linkKind`); the accessor now lives at `./parent-link.ts`.
6005
+ * Parent lifetime semantics are represented directly by the generic IR relation.
6052
6006
  */ function readLottieSpecific(layer) {
6053
6007
  var _layer_specific;
6054
6008
  return (_layer_specific = layer.specific) == null ? void 0 : _layer_specific.lottie;
@@ -6058,6 +6012,8 @@ exports.DEFAULT_CAMERA_FOV = DEFAULT_CAMERA_FOV;
6058
6012
  exports.DEFAULT_CAMERA_Z = DEFAULT_CAMERA_Z;
6059
6013
  exports.DEFAULT_CLIP_MODE = DEFAULT_CLIP_MODE;
6060
6014
  exports.assembleScene = assembleScene;
6015
+ exports.buildNormalizedColorAnimation = buildNormalizedColorAnimation;
6016
+ exports.buildNormalizedTransformAnimation = buildNormalizedTransformAnimation;
6061
6017
  exports.buildTimelineTracks = buildTimelineTracks;
6062
6018
  exports.convert2dTo3dPoint = convert2dTo3dPoint;
6063
6019
  exports.convertGEToIR = convertGEToIR;
@@ -6065,10 +6021,15 @@ exports.convertIRToGE = convertIRToGE;
6065
6021
  exports.createId = createId;
6066
6022
  exports.estimateTextWidth = estimateTextWidth;
6067
6023
  exports.get2dTo3dRatio = get2dTo3dRatio;
6024
+ exports.getEffectsCompositionSpecific = getEffectsCompositionSpecific;
6025
+ exports.getEffectsLayerSpecific = getEffectsLayerSpecific;
6026
+ exports.hasEffectsAnimationPassthrough = hasEffectsAnimationPassthrough;
6027
+ exports.hasEffectsColorAnimationPassthrough = hasEffectsColorAnimationPassthrough;
6028
+ exports.hasIndependentParentLifetime = hasIndependentParentLifetime;
6029
+ exports.invalidateEffectsLayerSpecific = invalidateEffectsLayerSpecific;
6068
6030
  exports.irPositionKeyframesToGE = irPositionKeyframesToGE;
6069
6031
  exports.irScalarKeyframesToGE = irScalarKeyframesToGE;
6070
6032
  exports.irVectorKeyframesToGE = irVectorKeyframesToGE;
6071
- exports.isTransformOnlyParentLink = isTransformOnlyParentLink;
6072
6033
  exports.lerp = lerp;
6073
6034
  exports.normalizeChildVisibilityByParentDelays = normalizeChildVisibilityByParentDelays;
6074
6035
  exports.readLottieSpecific = readLottieSpecific;