Address review comments; fix arc flattening logic
diff --git a/crates/encoding/src/math.rs b/crates/encoding/src/math.rs
index 8efbff0..bb3224d 100644
--- a/crates/encoding/src/math.rs
+++ b/crates/encoding/src/math.rs
@@ -123,7 +123,7 @@
 }
 
 /// Convertes a 16-bit precision IEEE-754 binary16 float to a f32.
-/// This implementation was adapted from Fabian Giesen's `half_to_float`()
+/// This implementation was adapted from Fabian Giesen's `half_to_float()`
 /// function which can be found at <https://gist.github.com/rygorous/2156668#file-gistfile1-cpp-L574>
 pub fn f16_to_f32(bits: u16) -> f32 {
     let bits = bits as u32;
diff --git a/shader/flatten.wgsl b/shader/flatten.wgsl
index e128915..f90e265 100644
--- a/shader/flatten.wgsl
+++ b/shader/flatten.wgsl
@@ -297,17 +297,16 @@
     var p0 = transform_apply(transform, begin);
     var r = begin - center;
 
-    let EPS = 1e-9;
-    let tol = 0.5;
+    let MIN_THETA = 0.0001;
+    let tol = 0.1;
     let radius = max(tol, length(p0 - transform_apply(transform, center)));
-    let x = 1. - tol / radius;
-    let theta = acos(clamp(2. * x * x - 1., -1., 1.));
-    let MAX_LINES = 1000u;
-    let n_lines = select(min(MAX_LINES, u32(ceil(6.2831853 / theta))), MAX_LINES, theta <= EPS);
+    let theta = max(MIN_THETA, 2. * acos(1. - tol / radius));
 
-    let th = angle / f32(n_lines);
-    let c = cos(th);
-    let s = sin(th);
+    // Always output at least one line so that we always draw the chord.
+    let n_lines = max(1u, u32(ceil(angle / theta)));
+
+    let c = cos(theta);
+    let s = sin(theta);
     let rot = mat2x2(c, -s, s, c);
 
     let line_ix = atomicAdd(&bump.lines, n_lines);
diff --git a/src/cpu_shader/flatten.rs b/src/cpu_shader/flatten.rs
index 0f0e378..fba7173 100644
--- a/src/cpu_shader/flatten.rs
+++ b/src/cpu_shader/flatten.rs
@@ -126,6 +126,12 @@
     bbox: &mut IntBbox,
     lines: &mut [LineSoup],
 ) {
+    assert!(
+        !p0.is_nan() && !p1.is_nan(),
+        "wrote line segment with NaN: p0: {:?}, p1: {:?}",
+        p0,
+        p1
+    );
     bbox.add_pt(p0);
     bbox.add_pt(p1);
     lines[line_ix] = LineSoup {
@@ -322,22 +328,19 @@
     lines: &mut [LineSoup],
     bbox: &mut IntBbox,
 ) {
+    const MIN_THETA: f32 = 0.0001;
+
     let mut p0 = transform.apply(begin);
     let mut r = begin - center;
-    let tol: f32 = 0.5;
+    let tol: f32 = 0.1;
     let radius = tol.max((p0 - transform.apply(center)).length());
-    let x = 1. - tol / radius;
-    let theta = (2. * x * x - 1.).clamp(-1., 1.).acos();
-    const MAX_LINES: u32 = 1000;
-    let n_lines = if theta <= ROBUST_EPSILON {
-        MAX_LINES
-    } else {
-        MAX_LINES.min((std::f32::consts::TAU / theta).ceil() as u32)
-    };
+    let theta = (2. * (1. - tol / radius).acos()).max(MIN_THETA);
 
-    let th = angle / (n_lines as f32);
-    let c = th.cos();
-    let s = th.sin();
+    // Always output at least one line so that we always draw the chord.
+    let n_lines = ((angle / theta).ceil() as u32).max(1);
+
+    let c = theta.cos();
+    let s = theta.sin();
     let rot = Transform([c, -s, s, c, 0., 0.]);
 
     for _ in 0..(n_lines - 1) {
diff --git a/src/cpu_shader/util.rs b/src/cpu_shader/util.rs
index ef0bb5b..da66f7b 100644
--- a/src/cpu_shader/util.rs
+++ b/src/cpu_shader/util.rs
@@ -102,6 +102,10 @@
     pub fn normalize(self) -> Vec2 {
         self / self.length()
     }
+
+    pub fn is_nan(&self) -> bool {
+        self.x.is_nan() || self.y.is_nan()
+    }
 }
 
 #[derive(Clone)]