Diagonal square works
diff --git a/issue-repro/src/main/java/com/airbnb/lottie/issues/IssueReproActivity.kt b/issue-repro/src/main/java/com/airbnb/lottie/issues/IssueReproActivity.kt
index 7fc7b8a..80f04ca 100755
--- a/issue-repro/src/main/java/com/airbnb/lottie/issues/IssueReproActivity.kt
+++ b/issue-repro/src/main/java/com/airbnb/lottie/issues/IssueReproActivity.kt
@@ -2,8 +2,17 @@
 
 import android.os.Bundle
 import androidx.activity.compose.setContent
-import androidx.annotation.FloatRange
 import androidx.appcompat.app.AppCompatActivity
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.unit.dp
 import com.airbnb.lottie.compose.LottieAnimationSpec
 import com.airbnb.lottie.compose.LottieAnimationState
 import com.airbnb.lottie.compose.rememberLottieComposition
@@ -19,10 +28,19 @@
                 isPlaying = true,
                 repeatCount = Integer.MAX_VALUE,
             )
-            ComposeLottieAnimation(
-                compositionResult,
-                state,
-            )
+            Column(
+                verticalArrangement = Arrangement.Center,
+                horizontalAlignment = Alignment.CenterHorizontally,
+                modifier = Modifier.fillMaxSize(),
+            ) {
+                ComposeLottieAnimation(
+                    compositionResult,
+                    state,
+                    modifier = Modifier
+                        .size(256.dp)
+                        .background(Color.Blue)
+                )
+            }
         }
     }
 }
diff --git a/issue-repro/src/main/res/raw/anim.json b/issue-repro/src/main/res/raw/anim.json
index 072ccdb..8ac014b 100644
--- a/issue-repro/src/main/res/raw/anim.json
+++ b/issue-repro/src/main/res/raw/anim.json
@@ -1 +1 @@
-{"v":"5.7.4","fr":60,"ip":0,"op":61,"w":400,"h":400,"nm":"Test","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[150,150],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-125,-125],"to":[41.667,41.667],"ti":[-41.667,-41.667]},{"t":60,"s":[125,125]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":61,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
+{"v":"5.7.4","fr":60,"ip":0,"op":181,"w":400,"h":400,"nm":"Diagonal","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"Shape Layer 1","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[200,200,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[150,150],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":0,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[1,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":0,"s":[-125,-125],"to":[41.667,41.667],"ti":[-41.667,-41.667]},{"t":180,"s":[125,125]}],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LayerTransform.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/ComposeLottieTransform.kt
similarity index 70%
rename from lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LayerTransform.kt
rename to lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/ComposeLottieTransform.kt
index 4974626..ece86b3 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LayerTransform.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/ComposeLottieTransform.kt
@@ -3,14 +3,14 @@
 import android.graphics.PointF
 import androidx.compose.runtime.*
 import androidx.compose.ui.Modifier
-import androidx.compose.ui.composed
 import androidx.compose.ui.graphics.graphicsLayer
 import com.airbnb.lottie.model.animatable.AnimatableTransform
+import com.airbnb.lottie.model.content.ShapeGroup
 import com.airbnb.lottie.model.layer.Layer
 import com.airbnb.lottie.value.Keyframe
 import kotlin.properties.Delegates
 
-fun Modifier.withTransform(transform: LayerTransform): Modifier {
+fun Modifier.withTransform(transform: ComposeLottieTransform): Modifier {
     if (transform.isIdentity) return this
 
     // TODO: maybe use composed {}
@@ -22,7 +22,26 @@
     )
 }
 
-class LayerTransform(private val transform: AnimatableTransform?) {
+@Composable
+fun rememberTransform(layer: Layer): ComposeLottieTransform {
+    val animatableTransform = remember(layer) { layer.transform }
+    return rememberTransform(animatableTransform)
+}
+
+@Composable
+fun rememberTransform(shapeGroup: ShapeGroup): ComposeLottieTransform {
+    val animatableTransform = remember(shapeGroup) { shapeGroup.items.lastOrNull() as? AnimatableTransform }
+    return rememberTransform(animatableTransform)
+}
+
+@Composable
+fun rememberTransform(transform: AnimatableTransform?): ComposeLottieTransform {
+    val composeTransform = remember(transform) { ComposeLottieTransform(transform) }
+    composeTransform.progress = LocalLottieProgress.current
+    return composeTransform
+}
+
+class ComposeLottieTransform(private val transform: AnimatableTransform?) {
     var progress by Delegates.observable(0f) { _, oldValue, newValue ->
         if (oldValue == newValue) return@observable
         updatePosition(newValue)
@@ -30,7 +49,7 @@
 
     private var positionProgress = 0f
     private var positionKeyframeIndex = 0
-    private var _position = mutableStateOf(POINT_F)
+    private var _position = mutableStateOf(PointF())
     val position: PointF by _position
 
     val isIdentity get() = transform == null || position.equals(0f, 0f)
@@ -50,10 +69,6 @@
             lerp(keyframe.startValue?.y ?: 0f, keyframe.endValue?.y ?: 0f, interpolatedProgress),
         )
     }
-
-    companion object {
-        private val POINT_F = PointF()
-    }
 }
 
 private fun <T> List<Keyframe<T>>.findKeyframeIndex(progress: Float, currentKeyframeIndex: Int): Keyframe<T> {
diff --git a/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LottieComposeRenderer.kt b/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LottieComposeRenderer.kt
index 20cb2c0..c50b0d8 100644
--- a/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LottieComposeRenderer.kt
+++ b/lottie-compose/src/main/java/com/airbnb/lottie/compose/renderer/LottieComposeRenderer.kt
@@ -3,7 +3,6 @@
 import android.graphics.PointF
 import android.util.Log
 import androidx.compose.foundation.Image
-import androidx.compose.foundation.layout.size
 import androidx.compose.runtime.*
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.graphics.Color
@@ -13,7 +12,6 @@
 import com.airbnb.lottie.LottieComposition
 import com.airbnb.lottie.compose.LottieAnimationState
 import com.airbnb.lottie.compose.LottieCompositionResult
-import com.airbnb.lottie.model.animatable.AnimatableTransform
 import com.airbnb.lottie.model.content.RectangleShape
 import com.airbnb.lottie.model.content.ShapeFill
 import com.airbnb.lottie.model.content.ShapeGroup
@@ -24,7 +22,11 @@
 val LocalLottieProgress = compositionLocalOf { 0f }
 
 @Composable
-fun ComposeLottieAnimation(compositionResult: LottieCompositionResult, state: LottieAnimationState) {
+fun ComposeLottieAnimation(
+    compositionResult: LottieCompositionResult,
+    state: LottieAnimationState,
+    modifier: Modifier = Modifier,
+) {
     if (compositionResult !is LottieCompositionResult.Success) return
     val composition = compositionResult.composition
 
@@ -62,8 +64,7 @@
                 Layer.LayerType.SHAPE -> Image(
                     shapeLayerPainter(composition, layer),
                     contentDescription = null,
-                    // TODO: use a different size
-                    modifier = Modifier.size(256.dp)
+                    modifier = modifier,
                 )
                 else -> Unit
             }
@@ -73,23 +74,20 @@
 
 @Composable
 fun shapeLayerPainter(composition: LottieComposition, layer: Layer): VectorPainter {
-    val progress = LocalLottieProgress.current
-    val animatableTransform = remember(layer) { layer.shapes.firstOrNull { it is AnimatableTransform } as? AnimatableTransform }
-    val transform = LayerTransform(animatableTransform)
-    LaunchedEffect(progress) {
-        transform.progress = progress
-    }
-
+    val transform = rememberTransform(layer)
     return rememberVectorPainter(
-        defaultWidth = 256.dp,
-        defaultHeight = 256.dp,
+        defaultWidth = composition.bounds.width().dp,
+        defaultHeight = composition.bounds.height().dp,
+        viewportWidth = composition.bounds.width().toFloat(),
+        viewportHeight = composition.bounds.height().toFloat(),
     ) { viewportWidth, viewportHeight ->
+        Log.d("Gabe", "shapeLayerPainter ${transform.position}")
         Group(
             name = layer.layerName,
             translationX = transform.position.x,
             translationY = transform.position.y,
-            scaleX = viewportWidth / composition.bounds.width(),
-            scaleY = viewportHeight / composition.bounds.height(),
+            scaleX = composition.bounds.width() / viewportWidth,
+            scaleY = composition.bounds.height() / viewportHeight,
         ) {
             PathData {
                 layer.shapes.forEach { shapeModel ->
@@ -106,18 +104,25 @@
 @Composable
 fun ComposeShapeGroup(shapeGroup: ShapeGroup) {
     if (shapeGroup.isHidden || shapeGroup.items.isEmpty()) return
-    val transform = remember(shapeGroup) { LayerTransform(shapeGroup.items.lastOrNull() as? AnimatableTransform) }
+    val transform = rememberTransform(shapeGroup)
     val pathData = remember { mutableListOf<PathNode>() }
-    val progress = LocalLottieProgress.current
-    LaunchedEffect(progress) {
-        transform.progress = progress
-    }
-    pathData.clear()
+
+    Log.d("Gabe", "ComposeShapeGroup ${transform.position}")
     Group(
         name = shapeGroup.name,
         translationX = transform.position.x,
         translationY = transform.position.y,
     ) {
+        // Reuse the list and clear it so that the backing array doesn't need to be recreated.
+        pathData.clear()
+        pathData += PathData {
+            moveTo(380f, 0f)
+            lineTo(400f, 0f)
+            lineTo(400f, 20f)
+            lineTo(380f, 20f)
+            lineTo(380f, 0f)
+            close()
+        }
         for (model in shapeGroup.items) {
             when (model) {
                 is RectangleShape -> {
@@ -127,7 +132,6 @@
                     ComposeShapeFill(model, pathData)
                 }
             }
-            Log.d("Gabe", "Drawing ${model::class.simpleName} $model")
         }
     }
 }
@@ -148,19 +152,23 @@
         lerp(sizeKeyframe.startValue?.y ?: 0f, sizeKeyframe.endValue?.y ?: 0f, interpolatedProgress),
     )
 
+    val halfWidth = size.x / 2f
+    val halfHeight = size.y / 2f
+
     return PathData {
-        moveTo(0f, 0f)
-        lineTo(size.x, 0f)
-        lineTo(size.x, size.y)
-        lineTo(0f, size.y)
-        lineTo(0f, 0f)
+        moveTo(-halfWidth, -halfHeight)
+        lineTo(halfWidth, -halfHeight)
+        lineTo(halfWidth, halfHeight)
+        lineTo(-halfWidth, halfHeight)
+        lineTo(-halfWidth, -halfHeight)
         close()
     }
 }
 
 @Composable
 fun ComposeShapeFill(fill: ShapeFill, pathData: List<PathNode>) {
-    Log.d("Gabe", "Drawing fill with ${pathData.size} nodes")
+    val colorAnimation = fill.color?.keyframes ?: return
+
     Path(
         pathData,
         // TODO: use the real color
diff --git a/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java b/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java
index 7bab3ab..fd4aa09 100644
--- a/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java
+++ b/lottie/src/main/java/com/airbnb/lottie/model/layer/Layer.java
@@ -149,7 +149,7 @@
     return shapes;
   }
 
-  AnimatableTransform getTransform() {
+  public AnimatableTransform getTransform() {
     return transform;
   }
 
diff --git a/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java b/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java
index baac4e5..136c1ee 100644
--- a/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java
+++ b/lottie/src/main/java/com/airbnb/lottie/utils/Utils.java
@@ -252,6 +252,7 @@
   }
 
   public static float dpScale() {
+    if (true) return 1;
     if (dpScale == -1) {
       dpScale = Resources.getSystem().getDisplayMetrics().density;
     }