diff --git a/geometry.go b/geometry.go
index 7353f1af389f360a63f2fa1e98a38265723c0ea7..593736100c958df20e1329e3cffef62836f550a8 100644
--- a/geometry.go
+++ b/geometry.go
@@ -310,14 +310,15 @@ func (r Rect) Intersect(s Rect) Rect {
 	return t
 }
 
-// IntersectsCircle returns whether the Circle and the Rect intersect.
+// IntersectsCircle returns a minimal required Vector, such that moving the circle by that vector would stop the Circle
+// and the Rect intersecting.  This function returns a zero-vector if the Circle and Rect do not overlap, and if only
+// the perimeters touch.
 //
 // This function will return true if:
 //  - The Rect contains the Circle, partially or fully
 //  - The Circle contains the Rect, partially of fully
-//  - An edge of the Rect is a tangent to the Circle
-func (r Rect) IntersectsCircle(c Circle) bool {
-	return c.IntersectsRect(r)
+func (r Rect) IntersectsCircle(c Circle) Vec {
+	return c.IntersectsRect(r).Scaled(-1)
 }
 
 // Circle is a 2D circle. It is defined by two properties:
@@ -467,24 +468,79 @@ func (c Circle) Intersect(d Circle) Circle {
 	}
 }
 
-// IntersectsRect returns whether the Circle and the Rect intersect.
+// IntersectsRect returns a minimal required Vector, such that moving the circle by that vector would stop the Circle
+// and the Rect intersecting.  This function returns a zero-vector if the Circle and Rect do not overlap, and if only
+// the perimeters touch.
 //
 // This function will return true if:
 //  - The Rect contains the Circle, partially or fully
 //  - The Circle contains the Rect, partially of fully
-//  - An edge of the Rect is a tangent to the Circle
-func (c Circle) IntersectsRect(r Rect) bool {
+func (c Circle) IntersectsRect(r Rect) Vec {
+	// h and v will hold the minimum horizontal and vertical distances (respectively) to avoid overlapping
+	var h, v float64
+
 	// Checks if the c.Center is not in the diagonal quadrants of the rectangle
 	if (r.Min.X <= c.Center.X && c.Center.X <= r.Max.X) || (r.Min.Y <= c.Center.Y && c.Center.Y <= r.Max.Y) {
 		// 'grow' the Rect by c.Radius in each orthagonal
-		return Rect{
-			Min: r.Min.Sub(V(c.Radius, c.Radius)),
-			Max: r.Max.Add(V(c.Radius, c.Radius)),
-		}.Contains(c.Center)
+		grown := Rect{Min: r.Min.Sub(V(c.Radius, c.Radius)), Max: r.Max.Add(V(c.Radius, c.Radius))}
+		if !grown.Contains(c.Center) {
+			// c.Center not close enough to overlap, return zero-vector
+			return ZV
+		}
+
+		// Get minimum distance to travel out of Rect
+		rToC := r.Center().To(c.Center)
+		h = c.Radius - math.Abs(rToC.X) + (r.W() / 2)
+		v = c.Radius - math.Abs(rToC.Y) + (r.H() / 2)
+
+		if rToC.X < 0 {
+			h = -h
+		}
+		if rToC.Y < 0 {
+			v = -v
+		}
+	} else {
+		// The center is in the diagonal quadrants
+		if c.Center.To(r.Min).Len() <= c.Radius {
+			// Closest to bottom-left
+			cornerToCenter := r.Min.To(c.Center)
+			// Get the horizontal and vertical overlaps
+			h = c.Radius - math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.Y, 2))
+			v = -1 * (c.Radius + math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.X, 2)))
+		}
+		if c.Center.To(r.Max).Len() <= c.Radius {
+			// Closest to top-right
+			cornerToCenter := r.Max.To(c.Center)
+			// Get the horizontal and vertical overlaps
+			h = c.Radius - math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.Y, 2))
+			v = c.Radius - math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.X, 2))
+		}
+		if c.Center.To(V(r.Min.X, r.Max.Y)).Len() <= c.Radius {
+			// Closest to top-left
+			cornerToCenter := V(r.Min.X, r.Max.Y).To(c.Center)
+			// Get the horizontal and vertical overlaps
+			h = -1 * (c.Radius + math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.Y, 2)))
+			v = c.Radius - math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.X, 2))
+		}
+		if c.Center.To(V(r.Max.X, r.Min.Y)).Len() <= c.Radius {
+			// Closest to bottom-right
+			cornerToCenter := V(r.Max.X, r.Min.Y).To(c.Center)
+			// Get the horizontal and vertical overlaps
+			h = -1 * (c.Radius + math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.Y, 2)))
+			v = -1 * (c.Radius + math.Sqrt(math.Pow(c.Radius, 2)-math.Pow(cornerToCenter.X, 2)))
+		}
+	}
+
+	// No intersect
+	if h == 0 && v == 0 {
+		return ZV
+	}
+
+	if math.Abs(h) > math.Abs(v) {
+		// Vertical distance shorter
+		return V(0, v)
 	}
-	// The center is in the diagonal quadrants
-	return c.Center.To(r.Min).Len() <= c.Radius || c.Center.To(r.Max).Len() <= c.Radius ||
-		c.Center.To(V(r.Min.X, r.Max.Y)).Len() <= c.Radius || c.Center.To(V(r.Max.X, r.Min.Y)).Len() <= c.Radius
+	return V(h, 0)
 }
 
 // Matrix is a 2x3 affine matrix that can be used for all kinds of spatial transforms, such
diff --git a/geometry_test.go b/geometry_test.go
index eec854de9fb4776d0f6b8b1c8a4a1d23644302c6..2bdc2840985dfe79ab3fc2b53c05c6e0d1b8ee1d 100644
--- a/geometry_test.go
+++ b/geometry_test.go
@@ -469,55 +469,85 @@ func TestRect_IntersectsCircle(t *testing.T) {
 		name   string
 		fields fields
 		args   args
-		want   bool
+		want   pixel.Vec
 	}{
 		{
 			name:   "Rect.IntersectsCircle(): no overlap",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
 			args:   args{c: pixel.C(pixel.V(50, 50), 1)},
-			want:   false,
+			want:   pixel.ZV,
 		},
 		{
 			name:   "Rect.IntersectsCircle(): circle contains rect",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
 			args:   args{c: pixel.C(pixel.V(5, 5), 10)},
-			want:   true,
+			want:   pixel.V(-15, 0),
 		},
 		{
 			name:   "Rect.IntersectsCircle(): rect contains circle",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
 			args:   args{c: pixel.C(pixel.V(5, 5), 1)},
-			want:   true,
+			want:   pixel.V(-6, 0),
 		},
 		{
 			name:   "Rect.IntersectsCircle(): circle overlaps bottom-left corner",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
-			args:   args{c: pixel.C(pixel.V(-.5, -.5), 1)},
-			want:   true,
+			args:   args{c: pixel.C(pixel.V(0, 0), 1)},
+			want:   pixel.V(1, 0),
 		},
 		{
 			name:   "Rect.IntersectsCircle(): circle overlaps top-left corner",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
-			args:   args{c: pixel.C(pixel.V(-.5, 10.5), 1)},
-			want:   true,
+			args:   args{c: pixel.C(pixel.V(0, 10), 1)},
+			want:   pixel.V(1, 0),
+		},
+		{
+			name:   "Rect.IntersectsCircle(): circle overlaps bottom-right corner",
+			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
+			args:   args{c: pixel.C(pixel.V(10, 0), 1)},
+			want:   pixel.V(-1, 0),
+		},
+		{
+			name:   "Rect.IntersectsCircle(): circle overlaps top-right corner",
+			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
+			args:   args{c: pixel.C(pixel.V(10, 10), 1)},
+			want:   pixel.V(-1, 0),
 		},
 		{
 			name:   "Rect.IntersectsCircle(): circle overlaps two corners",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
 			args:   args{c: pixel.C(pixel.V(0, 5), 6)},
-			want:   true,
+			want:   pixel.V(6, 0),
 		},
 		{
-			name:   "Rect.IntersectsCircle(): circle overlaps one edge",
+			name:   "Rect.IntersectsCircle(): circle overlaps left edge",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
 			args:   args{c: pixel.C(pixel.V(0, 5), 1)},
-			want:   true,
+			want:   pixel.V(1, 0),
+		},
+		{
+			name:   "Rect.IntersectsCircle(): circle overlaps bottom edge",
+			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
+			args:   args{c: pixel.C(pixel.V(5, 0), 1)},
+			want:   pixel.V(0, 1),
+		},
+		{
+			name:   "Rect.IntersectsCircle(): circle overlaps right edge",
+			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
+			args:   args{c: pixel.C(pixel.V(10, 5), 1)},
+			want:   pixel.V(-1, 0),
+		},
+		{
+			name:   "Rect.IntersectsCircle(): circle overlaps top edge",
+			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
+			args:   args{c: pixel.C(pixel.V(5, 10), 1)},
+			want:   pixel.V(0, -1),
 		},
 		{
 			name:   "Rect.IntersectsCircle(): edge is tangent",
 			fields: fields{Min: pixel.ZV, Max: pixel.V(10, 10)},
 			args:   args{c: pixel.C(pixel.V(-1, 5), 1)},
-			want:   true,
+			want:   pixel.ZV,
 		},
 	}
 	for _, tt := range tests {