diff --git a/native/components/full-screen-view-modal.react.js b/native/components/full-screen-view-modal.react.js
--- a/native/components/full-screen-view-modal.react.js
+++ b/native/components/full-screen-view-modal.react.js
@@ -57,7 +57,6 @@
   clamp,
   gestureJustStarted,
   gestureJustEnded,
-  runTiming,
   clampV2,
 } from '../utils/animation-utils.js';
 
@@ -351,17 +350,6 @@
     );
 
     const updates = [
-      this.recenter(
-        resetXClock,
-        resetYClock,
-        activeInteraction,
-        recenteredScale,
-        horizontalPanSpace,
-        verticalPanSpace,
-        curScale,
-        curX,
-        curY,
-      ),
       this.flingUpdate(
         resetXClock,
         resetYClock,
@@ -441,56 +429,6 @@
     return max(vertPop, 0);
   }
 
-  recenter(
-    // Inputs
-    resetXClock: Clock,
-    resetYClock: Clock,
-    activeInteraction: Node,
-    recenteredScale: Node,
-    horizontalPanSpace: Node,
-    verticalPanSpace: Node,
-    // Outputs
-    curScale: Value,
-    curX: Value,
-    curY: Value,
-  ): Node {
-    const resetScaleClock = new Clock();
-
-    const recenteredX = clamp(
-      curX,
-      multiply(-1, horizontalPanSpace),
-      horizontalPanSpace,
-    );
-    const recenteredY = clamp(
-      curY,
-      multiply(-1, verticalPanSpace),
-      verticalPanSpace,
-    );
-
-    return cond(
-      activeInteraction,
-      [
-        stopClock(resetScaleClock),
-        stopClock(resetXClock),
-        stopClock(resetYClock),
-      ],
-      [
-        cond(
-          or(clockRunning(resetScaleClock), neq(recenteredScale, curScale)),
-          set(curScale, runTiming(resetScaleClock, curScale, recenteredScale)),
-        ),
-        cond(
-          or(clockRunning(resetXClock), neq(recenteredX, curX)),
-          set(curX, runTiming(resetXClock, curX, recenteredX)),
-        ),
-        cond(
-          or(clockRunning(resetYClock), neq(recenteredY, curY)),
-          set(curY, runTiming(resetYClock, curY, recenteredY)),
-        ),
-      ],
-    );
-  }
-
   flingUpdate(
     // Inputs
     resetXClock: Clock,
@@ -1034,6 +972,8 @@
       );
     });
 
+    const isRunningDismissAnimation = useSharedValue(false);
+
     const panEnd = React.useCallback(
       ({ velocityX, velocityY }: PanGestureEvent) => {
         'worklet';
@@ -1047,6 +987,7 @@
         );
         const shouldGoBack = velocity > 50 || 0.7 > progressiveOpacity.value;
         if (shouldGoBack && !pinchActive.value && roundedCurScale.value <= 1) {
+          isRunningDismissAnimation.value = true;
           curX.value = withDecay({ velocity: velocityX, ...decayConfig });
           curY.value = withDecay({ velocity: velocityY, ...decayConfig });
           cancelAnimation(curScale);
@@ -1062,6 +1003,7 @@
         pinchActive,
         roundedCurScale,
         curScale,
+        isRunningDismissAnimation,
       ],
     );
 
@@ -1139,6 +1081,8 @@
       [outsideButtons, toggleActionLinks, toggleCloseButton, roundedCurScale],
     );
 
+    const isRunningDoubleTapZoomAnimation = useSharedValue(false);
+
     const doubleTapUpdate = React.useCallback(
       ({ x, y }: TapGestureEvent) => {
         'worklet';
@@ -1171,7 +1115,12 @@
         const targetX = tapXPercentClamped * imageWidth.value * targetScale;
         const targetY = tapYPercentClamped * imageHeight.value * targetScale;
 
-        curScale.value = withTiming(targetScale, defaultTimingConfig);
+        isRunningDoubleTapZoomAnimation.value = true;
+        curScale.value = withTiming(
+          targetScale,
+          defaultTimingConfig,
+          () => (isRunningDoubleTapZoomAnimation.value = false),
+        );
         curX.value = withTiming(targetX, defaultTimingConfig);
         curY.value = withTiming(targetY, defaultTimingConfig);
       },
@@ -1187,6 +1136,7 @@
         outsideButtons,
         roundedCurScale,
         getVerticalPanSpace,
+        isRunningDoubleTapZoomAnimation,
       ],
     );
 
@@ -1211,6 +1161,41 @@
       return progressiveOpacity.value;
     });
 
+    useAnimatedReaction(
+      () =>
+        pinchActive.value ||
+        panActive.value ||
+        isRunningDismissAnimation.value ||
+        isRunningDoubleTapZoomAnimation.value,
+      activeInteraction => {
+        if (activeInteraction) {
+          return;
+        }
+        const recenteredScale = Math.max(curScale.value, 1);
+        const horizontalPanSpace = getHorizontalPanSpace(recenteredScale);
+        const verticalPanSpace = getVerticalPanSpace(recenteredScale);
+        const recenteredX = clampV2(
+          curX.value,
+          -horizontalPanSpace,
+          horizontalPanSpace,
+        );
+        const recenteredY = clampV2(
+          curY.value,
+          -verticalPanSpace,
+          verticalPanSpace,
+        );
+        if (curScale.value !== recenteredScale) {
+          curScale.value = withTiming(recenteredScale, defaultTimingConfig);
+        }
+        if (curX.value !== recenteredX) {
+          curX.value = withTiming(recenteredX, defaultTimingConfig);
+        }
+        if (curY.value !== recenteredY) {
+          curY.value = withTiming(recenteredY, defaultTimingConfig);
+        }
+      },
+    );
+
     const gesture = React.useMemo(() => {
       const pinchGesture = Gesture.Pinch()
         .onStart(pinchStart)