diff --git a/apps/plugins/pictureflow.c b/apps/plugins/pictureflow.c
index cd7e54c..e3e7836 100644
--- a/apps/plugins/pictureflow.c
+++ b/apps/plugins/pictureflow.c
@@ -111,6 +111,9 @@ typedef fb_data pix_t;
 #define REFLECT_SC ((0x10000U * 3 + (REFLECT_HEIGHT * 5 - 1)) / \
     (REFLECT_HEIGHT * 5))
 #define DISPLAY_OFFS ((LCD_HEIGHT / 2) - REFLECT_HEIGHT)
+#define CAM_DIST MAX(MIN(LCD_HEIGHT,LCD_WIDTH),120)
+#define CAM_DIST_R (CAM_DIST << PFREAL_SHIFT)
+#define DISPLAY_LEFT_R (PFREAL_HALF - LCD_WIDTH * PFREAL_ONE / 2)
 
 #define SLIDE_CACHE_SIZE 100
 
@@ -235,7 +238,6 @@ static struct configdata config[] =
 /** below we allocate the memory we want to use **/
 
 static pix_t *buffer; /* for now it always points to the lcd framebuffer */
-static PFreal rays[LCD_WIDTH];
 static uint16_t reflect_table[REFLECT_HEIGHT];
 static struct slide_data center_slide;
 static struct slide_data left_slides[MAX_SLIDES_COUNT];
@@ -337,6 +339,16 @@ static inline PFreal fmul(PFreal a, PFreal b)
     return (a*b) >> PFREAL_SHIFT;
 }
 
+/**
+ * This version preshifts each operand, which is useful when we know how many
+ * of the least significant bits will be empty, or are worried about overflow
+ * in a particular calculation
+ */
+static inline PFreal fmuln(PFreal a, PFreal b, int ps1, int ps2)
+{
+    return ((a >> ps1) * (b >> ps2)) >> (PFREAL_SHIFT - ps1 - ps2);
+}
+
 /* ARMv5+ has a clz instruction equivalent to our function.
  */
 #if (defined(CPU_ARM) && (ARM_ARCH > 4))
@@ -1154,23 +1166,28 @@ void reset_slides(void)
 /**
  Updates look-up table and other stuff necessary for the rendering.
  Call this when the viewport size or slide dimension is changed.
+ *
+ * To calculate the offset that will provide the proper margin, we use the same
+ * projection used to render the slides. Assuming zo == 0, the solution for xc,
+ * the slide center, is:
+ *                         xp * xs * sin(r)
+ * xc = xp - xs * cos(r) + ────────────────
+ *                                z
+ * TODO: support moving the side slides toward or away from the camera
  */
-void recalc_table(void)
+void recalc_offsets(void)
 {
-    int w = (LCD_WIDTH + 1) / 2;
-    int h = (LCD_HEIGHT + 1) / 2;
-    int i;
-    for (i = 0; i < w; i++) {
-        PFreal gg = (PFREAL_HALF + i * PFREAL_ONE) / (2 * h);
-        rays[w - i - 1] = -gg;
-        rays[w + i] = gg;
-    }
+    PFreal xs = PFREAL_HALF - DISPLAY_WIDTH * PFREAL_HALF;
+    PFreal xp = DISPLAY_WIDTH * PFREAL_HALF - PFREAL_HALF + center_margin *
+        PFREAL_ONE;
+    PFreal cosr, sinr;
 
     itilt = 70 * IANGLE_MAX / 360;      /* approx. 70 degrees tilted */
-
-    offsetX = DISPLAY_WIDTH / 2 * (fsin(itilt) + PFREAL_ONE);
+    cosr = fcos(-itilt);
+    sinr = fsin(-itilt);
+    offsetX = xp - fmul(xs, cosr) + fmuln(xp,
+        fmuln(xs, sinr, PFREAL_SHIFT - 2, 0), PFREAL_SHIFT - 2, 0)/CAM_DIST;
     offsetY = DISPLAY_WIDTH / 2 * (fsin(itilt) + PFREAL_ONE / 2);
-    offsetX += center_margin << PFREAL_SHIFT;
 }
 
 
@@ -1207,8 +1224,28 @@ static inline pix_t fade_color(pix_t c, unsigned int a)
 #endif
 
 /**
-  Render a single slide
-*/
+ * Render a single slide
+ * Where xc is the slide's horizontal offset from center, xs is the horizontal
+ * on the slide from its center, zo is the slide's depth offset from the plane
+ * of the display, r is the angle at which the slide is tilted, and xp is the
+ * point on the display corresponding to xs on the slide, the projection
+ * formulas are:
+ *
+ *      z * (xc + xs * cos(r))
+ * xp = ──────────────────────
+ *       z + zo + xs * sin(r)
+ *
+ *      z * (xc - xp) - xp * zo
+ * xs = ────────────────────────
+ *      xp * sin(r) - z * cos(r)
+ *
+ * We use the xp projection once, to find the left edge of the slide on the
+ * display. From there, we use the xs reverse projection to find the horizontal
+ * offset from the slide center of each column on the screen, until we reach
+ * the right edge of the slide, or the screen. The reverse projection can be
+ * optimized by saving the numerator and denominator of the fraction, which can
+ * then be incremented by (z + zo) and sin(r) respectively.
+ */
 void render_slide(struct slide_data *slide, const int alpha)
 {
     struct bitmap *bmp = surface(slide->slide_index);
@@ -1219,112 +1256,118 @@ void render_slide(struct slide_data *slide, const int alpha)
 
     const int sw = bmp->width;
     const int sh = bmp->height;
+    const PFreal slide_left = -sw * PFREAL_HALF + PFREAL_HALF;
 
     const int h = LCD_HEIGHT;
     const int w = LCD_WIDTH;
 
 
-    int distance = (h + slide->distance) * 100 / zoom;
-    if (distance < 100 ) distance = 100; /* clamp distances */
-    PFreal dist = distance * PFREAL_ONE;
-    PFreal sdx = fcos(slide->angle);
-    PFreal sdy = fsin(slide->angle);
-    PFreal xs = slide->cx - sw * fdiv(sdx, dist) / 2;
-
-    int xi = fmax(0, xs) >> PFREAL_SHIFT;
+    PFreal zo = (CAM_DIST_R + PFREAL_ONE * slide->distance) * 100 / zoom -
+        CAM_DIST_R;
+    PFreal cosr = fcos(slide->angle);
+    PFreal sinr = fsin(slide->angle);
+    PFreal xs = slide_left, xsnum, xsnumi, xsden, xsdeni;
+    PFreal xp = fdiv(CAM_DIST * (slide->cx + fmul(xs, cosr)),
+        (CAM_DIST_R + zo + fmul(xs,sinr)));
+
+    /* Since we're finding the screen position of the left edge of the slide,
+     * we round up.
+     */
+    int xi = (fmax(DISPLAY_LEFT_R, xp) - DISPLAY_LEFT_R + PFREAL_ONE - 1)
+        >> PFREAL_SHIFT;
+    xp = DISPLAY_LEFT_R + xi * PFREAL_ONE;
     if (xi >= w) {
         return;
     }
-
+    xsnum = CAM_DIST * (slide->cx - xp) - fmuln(xp, zo, PFREAL_SHIFT - 2, 0);
+    xsden = fmuln(xp, sinr, PFREAL_SHIFT - 2, 0) - CAM_DIST * cosr;
+    xs = fdiv(xsnum, xsden);
+    
+    xsnumi = -CAM_DIST_R - zo;
+    xsdeni = sinr;
     int x;
-    for (x = fmax(xi, 0); x < w; x++) {
-        PFreal hity = 0;
-        PFreal fk = rays[x];
-        if (sdy) {
-            fk = fk - fdiv(sdx, sdy);
-            if (fk)
-                hity = -fdiv(( rays[x] * distance
-                       - slide->cx
-                       + slide->cy * sdx / sdy), fk);
-        }
-
-        dist = distance * PFREAL_ONE + hity;
-        if (dist < 0)
-            continue;
-
-        PFreal hitx = fmul(dist, rays[x]);
-
-        PFreal hitdist = fdiv(hitx - slide->cx, sdx);
-
-        const int column = (sw >> 1) + (hitdist >> PFREAL_SHIFT);
+    int dy = PFREAL_ONE;
+    for (x = xi; x < w; x++) {
+        int column = (xs - slide_left) / PFREAL_ONE;
         if (column >= sw)
             break;
-        if (column < 0)
-            continue;
-
-        int y1 = (LCD_HEIGHT / 2) - 1;
-        int y2 = y1 + 1;
-        pix_t *pixel1 = &buffer[y1 * BUFFER_WIDTH + x];
-        pix_t *pixel2 = &buffer[y2 * BUFFER_WIDTH + x];
-        const int pixelstep = pixel2 - pixel1;
-
-        int dy = dist / h;
-        int p1 = (bmp->height - 1 - (DISPLAY_OFFS)) * PFREAL_ONE;
-        int p2 = p1 + dy;
-        const pix_t *ptr = &src[column * bmp->height];
-
-        if (alpha == 256)
+        if (column > 0)
         {
-            while ((y1 >= 0) && (p1 >= 0))
-            {
-                *pixel1 = ptr[p1 >> PFREAL_SHIFT];
-                p1 -= dy;
-                y1--;
-                pixel1 -= pixelstep;
-            }
-            while ((p2 < sh * PFREAL_ONE) && (y2 < h))
+            if (zo || slide->angle)
+                dy = (CAM_DIST_R + zo + fmul(xs, sinr)) / CAM_DIST;
+            int y1 = (LCD_HEIGHT / 2) - 1;
+            int y2 = y1 + 1;
+            pix_t *pixel1 = &buffer[y1 * BUFFER_WIDTH + x];
+            pix_t *pixel2 = pixel1 + BUFFER_WIDTH;
+            const int pixelstep = BUFFER_WIDTH;
+
+            int p1 = (bmp->height - 1 - (DISPLAY_OFFS)) * PFREAL_ONE;
+            int p2 = p1 + dy;
+            const pix_t *ptr = &src[column * bmp->height];
+
+            if (alpha == 256)
             {
-                *pixel2 = ptr[p2 >> PFREAL_SHIFT];
-                p2 += dy;
-                y2++;
-                pixel2 += pixelstep;
+                while ((y1 >= 0) && (p1 >= 0))
+                {
+                    *pixel1 = ptr[p1 >> PFREAL_SHIFT];
+                    p1 -= dy;
+                    y1--;
+                    pixel1 -= pixelstep;
+                }
+                while ((p2 < sh * PFREAL_ONE) && (y2 < h))
+                {
+                    *pixel2 = ptr[p2 >> PFREAL_SHIFT];
+                    p2 += dy;
+                    y2++;
+                    pixel2 += pixelstep;
+                }
+                while ((p2 < MIN(sh + REFLECT_HEIGHT, sh * 2) * PFREAL_ONE) &&
+                       (y2 < h))
+                {
+                    int ty = (p2 >> PFREAL_SHIFT) - sh;
+                    int lalpha = reflect_table[ty];
+                    *pixel2 = fade_color(ptr[sh - 1 - ty],lalpha);
+                    p2 += dy;
+                    y2++;
+                    pixel2 += pixelstep;
+                }
             }
-            while ((p2 < MIN(sh + REFLECT_HEIGHT, sh * 2) * PFREAL_ONE) &&
-                   (y2 < h))
+            else
             {
-                int ty = (p2 >> PFREAL_SHIFT) - sh;
-                int lalpha = reflect_table[ty];
-                *pixel2 = fade_color(ptr[sh - 1 - ty],lalpha);
-                p2 += dy;
-                y2++;
-                pixel2 += pixelstep;
+                while ((y1 >= 0) && (p1 >= 0))
+                {
+                    *pixel1 = fade_color(ptr[p1 >> PFREAL_SHIFT],alpha);
+                    p1 -= dy;
+                    y1--;
+                    pixel1 -= pixelstep;
+                }
+                while ((p2 < sh * PFREAL_ONE) && (y2 < h))
+                {
+                    *pixel2 = fade_color(ptr[p2 >> PFREAL_SHIFT],alpha);
+                    p2 += dy;
+                    y2++;
+                    pixel2 += pixelstep;
+                }
+                while ((p2 < MIN(sh + REFLECT_HEIGHT, sh * 2) * PFREAL_ONE) &&
+                       (y2 < h))
+                {
+                    int ty = (p2 >> PFREAL_SHIFT) - sh;
+                    int lalpha = (reflect_table[ty] * alpha + 128) >> 8;
+                    *pixel2 = fade_color(ptr[sh - 1 - ty],lalpha);
+                    p2 += dy;
+                    y2++;
+                    pixel2 += pixelstep;
+                }
             }
         }
-        else
-            while ((y1 >= 0) && (p1 >= 0))
-            {
-                *pixel1 = fade_color(ptr[p1 >> PFREAL_SHIFT],alpha);
-                p1 -= dy;
-                y1--;
-                pixel1 -= pixelstep;
-            }
-            while ((p2 < sh * PFREAL_ONE) && (y2 < h))
-            {
-                *pixel2 = fade_color(ptr[p2 >> PFREAL_SHIFT],alpha);
-                p2 += dy;
-                y2++;
-                pixel2 += pixelstep;
-            }
-            while ((p2 < MIN(sh + REFLECT_HEIGHT, sh * 2) * PFREAL_ONE) &&
-                   (y2 < h))
-            {
-                int ty = (p2 >> PFREAL_SHIFT) - sh;
-                int lalpha = (reflect_table[ty] * alpha + 128) >> 8;
-                *pixel2 = fade_color(ptr[sh - 1 - ty],lalpha);
-                p2 += dy;
-                y2++;
-                pixel2 += pixelstep;
-            }
+        if (zo || slide->angle)
+        {
+            xsnum += xsnumi;
+            xsden += xsdeni;
+            xs = fdiv(xsnum, xsden);
+        } else
+            xs += PFREAL_ONE;
+        
     }
     /* let the music play... */
     rb->yield();
@@ -1645,7 +1688,7 @@ int settings_menu(void)
                 rb->set_int("Spacing between slides", "", 1,
                             &slide_spacing,
                             NULL, 1, 0, 100, NULL );
-                recalc_table();
+                recalc_offsets();
                 reset_slides();
                 break;
 
@@ -1653,27 +1696,27 @@ int settings_menu(void)
                 rb->set_int("Center margin", "", 1,
                             &center_margin,
                             NULL, 1, 0, 80, NULL );
-                recalc_table();
+                recalc_offsets();
                 reset_slides();
                 break;
 
             case 3:
                 rb->set_int("Number of slides", "", 1, &num_slides,
                             NULL, 1, 1, MAX_SLIDES_COUNT, NULL );
-                recalc_table();
+                recalc_offsets();
                 reset_slides();
                 break;
 
             case 4:
                 rb->set_int("Zoom", "", 1, &zoom,
                             NULL, 1, 10, 300, NULL );
-                recalc_table();
+                recalc_offsets();
                 reset_slides();
                 break;
             case 5:
                 album_name_menu();
                 reset_track_list();
-                recalc_table();
+                recalc_offsets();
                 reset_slides();
                 break;
             case 6:
@@ -2037,7 +2080,7 @@ int main(void)
     target = 0;
     fade = 256;
 
-    recalc_table();
+    recalc_offsets();
     reset_slides();
 
     char fpstxt[10];