diff --git a/server/src/cmd.rs b/server/src/cmd.rs
index 7d6cf4156e..b4320967b6 100644
--- a/server/src/cmd.rs
+++ b/server/src/cmd.rs
@@ -2706,6 +2706,7 @@ rockiness {:?}
 tree_density {:?}
 in_river {:?}
 in_lake {:?}
+unbounded_water_level {:?}
 spawn_rate {:?} "#,
             wpos,
             alt,
@@ -2724,6 +2725,7 @@ spawn_rate {:?} "#,
             tree_density,
             col.in_river,
             col.in_lake,
+            col.unbounded_water_level,
             spawn_rate
         ))
     };
diff --git a/world/src/column/mod.rs b/world/src/column/mod.rs
index 162e20fcaf..060643ab12 100644
--- a/world/src/column/mod.rs
+++ b/world/src/column/mod.rs
@@ -123,7 +123,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
 
         let gradient = sim.get_gradient_approx(chunk_pos);
 
-        let lake_width = (TerrainChunkSize::RECT_SIZE.x as f64 * (2.0f64.sqrt())) + 2.0;
+        let lake_width = (TerrainChunkSize::RECT_SIZE.x as f64 * (2.0f64.sqrt())) + 6.0;
         let neighbor_river_data = neighbor_river_data.map(|(posj, chunkj, river)| {
             let kind = match river.river_kind {
                 Some(kind) => kind,
@@ -226,7 +226,24 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                     let coeffs =
                         river_spline_coeffs(neighbor_wpos, spline_derivative, neighbor_pass_wpos);
                     let direction = neighbor_wpos - neighbor_pass_wpos;
-                    if let Some((t, pt, dist)) = quadratic_nearest_point(&coeffs, wposf, Vec2::new(neighbor_wpos, neighbor_pass_wpos)) {
+
+                    if matches!(downhill_chunk.river.river_kind, Some(RiverKind::Lake { .. })) {
+                        let water_chunk = posj.map(|e| e as f64);
+                        let lake_width_noise = sim.gen_ctx.small_nz.get((wposf.map(|e| e as f64).div(32.0)).into_array());
+                        let water_aabr = Aabr {
+                            min: water_chunk * neighbor_coef + 4.0 - lake_width_noise * 8.0,
+                            max: (water_chunk + 1.0) * neighbor_coef - 4.0 + lake_width_noise * 8.0,
+                        };
+                        let pos = water_aabr.projected_point(wposf);
+                        (
+                            direction,
+                            coeffs,
+                            sim.get(neighbor_pass_pos).expect("Must already work"),
+                            0.5,
+                            pos,
+                            pos.distance(wposf),
+                        )
+                    } else if let Some((t, pt, dist)) = quadratic_nearest_point(&coeffs, wposf, Vec2::new(neighbor_wpos, neighbor_pass_wpos)) {
                         (
                             direction,
                             coeffs,
@@ -273,7 +290,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                 if let Some(RiverKind::River { cross_section }) = downhill_chunk.river.river_kind {
                     (cross_section.x as f64).min(river_width_min * 1.75) // Hack
                 } else if let Some(RiverKind::River { cross_section }) = chunkj.river.river_kind {
-                    cross_section.x as f64
+                    Lerp::lerp(cross_section.x as f64, lake_width, 0.5)
                 } else {
                     lake_width * 0.5
                 };
@@ -367,6 +384,10 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
             }
         }
 
+        fn is_waterfall(chunk_pos: Vec2<i32>, river_chunk: &SimChunk, downhill_chunk: &SimChunk) -> bool {
+            (chunk_pos.sum() as u32 % 19 < 2 || matches!(downhill_chunk.river.river_kind, Some(RiverKind::Lake { .. }))) && (river_chunk.water_alt > downhill_chunk.water_alt + 8.0)
+        }
+
         fn river_water_alt(a: f32, b: f32, t: f32, is_waterfall: bool) -> f32 {
             Lerp::lerp(
                 a,
@@ -381,22 +402,24 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                 if is_waterfall {
                     power(t as f64, 3.0 + (a - b).clamped(0.0, 16.0) as f64) as f32
                 } else {
-                    cubic(t as f64) as f32
+                    // cubic(t as f64) as f32
+                    t
                 },
             )
         }
 
         let actual_sea_level = CONFIG.sea_level + 2.0; // TODO: Don't add 2.0, why is this required?
 
-        let (river_water_level, in_river, lake_water_level, lake_dist, water_dist) = neighbor_river_data.clone().fold(
+        let (river_water_level, in_river, lake_water_level, lake_dist, water_dist, unbounded_water_level) = neighbor_river_data.clone().fold(
             (
-                WeightedSum::default().with_max(actual_sea_level), // TODO: Don't add 1.0
+                WeightedSum::default().with_max(actual_sea_level),
                 false,
-                WeightedSum::default().with_max(actual_sea_level), // TODO: Don't add 1.0
+                WeightedSum::default().with_max(actual_sea_level),
                 10000.0f32,
                 None,
+                WeightedSum::default().with_max(actual_sea_level),
             ),
-            |(mut river_water_level, mut in_river, mut lake_water_level, mut lake_dist, water_dist), (river_chunk_idx, river_chunk, river, dist_info)| match (river.river_kind, dist_info) {
+            |(mut river_water_level, mut in_river, mut lake_water_level, mut lake_dist, water_dist, mut unbounded_water_level), (river_chunk_idx, river_chunk, river, dist_info)| match (river.river_kind, dist_info) {
                 (
                     Some(kind/*RiverKind::River { cross_section }*/),
                     Some((_, dist, river_width, (river_t, (river_pos, _), downhill_chunk))),
@@ -413,12 +436,18 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                         RiverKind::River { .. } /*| RiverKind::Lake { .. }*/ => {
                             // Alt of river water *is* the alt of land
                             let river_water_alt = river_water_alt(
-                                river_chunk.alt,
-                                downhill_chunk.alt,
+                                river_chunk.alt.max(river_chunk.water_alt),
+                                downhill_chunk.alt.max(downhill_chunk.water_alt),
                                 river_t as f32,
-                                river_chunk_idx.sum() as u32 % 5 == 0,
+                                is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
                             );
 
+                            // if river_edge_dist > 0.0 {
+                            //     unbounded_water_level = unbounded_water_level
+                            //         .with(river_water_alt - (river_edge_dist - 2.0).max(0.0), 1.0 / (1.0 + river_edge_dist * 5.0))
+                            //         .with_max(river_water_alt - (river_edge_dist - 2.0).max(0.0));
+                            // }
+
                             river_water_level = river_water_level
                                 // .with_max(river_water_alt)
                                 .with(river_water_alt, near_center);
@@ -429,12 +458,20 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                         },
                         // Slightly wider threshold is chosen in case the lake bounds are a bit wrong
                         RiverKind::Lake { .. } => {
-                            let lake_water_alt = Lerp::lerp(
+                            let lake_water_alt = river_water_alt(
                                 river_chunk.alt.max(river_chunk.water_alt),
                                 downhill_chunk.alt.max(downhill_chunk.water_alt),
                                 river_t as f32,
+                                is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
                             );
 
+                            if river_edge_dist > 0.0 && river_width > lake_width * 0.99 /* !matches!(downhill_chunk.river.river_kind, Some(RiverKind::Lake { .. }))*/ {
+                                let unbounded_water_alt = lake_water_alt - ((river_edge_dist - 8.0).max(0.0) / 5.0).powf(2.0);
+                                unbounded_water_level = unbounded_water_level
+                                    .with(unbounded_water_alt, 1.0 / (1.0 + river_edge_dist * 5.0))
+                                    .with_max(unbounded_water_alt);
+                            }
+
                             river_water_level = river_water_level
                                 .with(lake_water_alt, near_center);
 
@@ -444,8 +481,8 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                             // }
 
                             // Lake border prevents a lake failing to propagate its altitude to nearby rivers
-                            let border = if river_width >= lake_width * 0.9 { 10.0 } else { 0.0 };
-                            if river_edge_dist <= border {
+                            let border = (river_width / lake_width) as f32 * 14.0;
+                            if river_edge_dist <= 0.0/*border*/ {
                                 lake_water_level = lake_water_level
                                     // Make sure the closest lake is prioritised
                                     .with(lake_water_alt, near_center + 0.1 / (1.0 + river_edge_dist));
@@ -458,14 +495,15 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                     let river_edge_dist_unclamped = (river_dist - river_width * 0.5) as f32;
                     let water_dist = Some(water_dist.unwrap_or(river_edge_dist_unclamped).min(river_edge_dist_unclamped));
 
-                    (river_water_level, in_river, lake_water_level, lake_dist, water_dist)
+                    (river_water_level, in_river, lake_water_level, lake_dist, water_dist, unbounded_water_level)
                 },
-                (_, _) => (river_water_level, in_river, lake_water_level, lake_dist, water_dist),
+                (_, _) => (river_water_level, in_river, lake_water_level, lake_dist, water_dist, unbounded_water_level),
             },
         );
+        let unbounded_water_level = unbounded_water_level.eval_or(actual_sea_level);
         let water_level = match (river_water_level.eval(), lake_water_level.eval().filter(|_| lake_dist <= 0.0 || in_river)) {
             (Some(r), Some(l)) => r.max(l),
-            (r, l) => r.or(l).unwrap_or(actual_sea_level),
+            (r, l) => r.or(l).unwrap_or(actual_sea_level).max(unbounded_water_level),
         };
 
         let riverless_alt = alt;
@@ -484,39 +522,45 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                     let near_river = ((river_dist / river_width) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);
 
                     let water_alt = match kind {
-                        RiverKind::River { .. } /*| RiverKind::Lake { .. }*/ => {
+                        RiverKind::River { cross_section } => {
                             // Alt of river water *is* the alt of land
                             let river_water_alt = river_water_alt(
-                                river_chunk.alt,
-                                downhill_chunk.alt,
-                                river_t as f32,
-                                river_chunk_idx.sum() as u32 % 5 == 0,
-                            );
-                            Some((river_water_alt, None))
-                        },
-                        RiverKind::Lake { .. } => {
-                            let lake_water_alt = Lerp::lerp(
                                 river_chunk.alt.max(river_chunk.water_alt),
                                 downhill_chunk.alt.max(downhill_chunk.water_alt),
                                 river_t as f32,
+                                is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
+                            );
+                            Some((river_water_alt, cross_section.y as f32, None))
+                        },
+                        RiverKind::Lake { .. } => {
+                            let lake_water_alt = river_water_alt(
+                                river_chunk.alt.max(river_chunk.water_alt),
+                                downhill_chunk.alt.max(downhill_chunk.water_alt),
+                                river_t as f32,
+                                is_waterfall(river_chunk_idx, river_chunk, downhill_chunk),
                             );
 
-                            Some((lake_water_alt, Some(riverless_alt)))
+                            let depth = water_level - Lerp::lerp(riverless_alt.min(water_level), water_level - 4.0, 0.5);
+
+                            let min_alt = Lerp::lerp(riverless_alt, lake_water_alt, ((river_dist - 7.5) / (river_width * 0.5 - 7.5).max(0.01)).clamped(0.0, 1.0) as f32);
+
+                            Some((lake_water_alt, /*river_width as f32 * 0.15*/ depth, Some(min_alt)))
                         },
                         RiverKind::Ocean => None,
                     };
 
                     const BANK_STRENGTH: f32 = 100.0;
-                    if let Some((water_alt, min_alt)) = water_alt {
+                    if let Some((water_alt, water_depth, min_alt)) = water_alt {
                         if river_edge_dist <= 0.0 {
                             const MIN_DEPTH: f32 = 1.0;
                             let near_centre = ((river_dist / (river_width * 0.5)) as f32).min(1.0).mul(f32::consts::PI).cos().add(1.0).mul(0.5);
-                            let waterfall_boost = if river_chunk_idx.sum() as u32 % 5 == 0 {
+                            let waterfall_boost = if is_waterfall(river_chunk_idx, river_chunk, downhill_chunk) {
                                 (river_chunk.alt - downhill_chunk.alt).max(0.0).powf(2.0) * (1.0 - (river_t as f32 - 0.5).abs() * 2.0).powf(3.5) / 20.0
                             } else {
                                 0.0
                             };
-                            let riverbed_depth = near_centre * river_width as f32 * 0.15 + MIN_DEPTH + waterfall_boost;
+                            // let river_depth = cross_section.y as f32 /*river_width as f32 * 0.15*/;
+                            let riverbed_depth = near_centre * water_depth + MIN_DEPTH + waterfall_boost;
                             // Handle rivers debouching into the ocean nicely by 'flattening' their bottom
                             let riverbed_alt = (water_alt - riverbed_depth).max(riverless_alt.min(CONFIG.sea_level - MIN_DEPTH));
                             alt
@@ -529,11 +573,18 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
                             // 'pulls' the riverbank toward the river's altitude to make sure that we get a smooth
                             // transition from normal terrain to the water.
                             let weight = Lerp::lerp(
-                                BANK_STRENGTH / (1.0 + (river_edge_dist as f32 - 2.0).max(0.0) * BANK_STRENGTH / BANK_SCALE),
+                                BANK_STRENGTH / (1.0 + (river_edge_dist as f32 - 3.0).max(0.0) * BANK_STRENGTH / BANK_SCALE),
                                 0.0,
-                                cubic((river_edge_dist / BANK_SCALE).clamped(0.0, 1.0) as f64) as f32,
+                                // cubic((river_edge_dist / BANK_SCALE).clamped(0.0, 1.0) as f64) as f32,
+                                (river_edge_dist / BANK_SCALE).clamped(0.0, 1.0),
                             );
                             let alt = alt.with(water_alt + GORGE, weight);
+
+                            let alt = if lake_dist > 0.0 && water_level < unbounded_water_level {
+                                alt.with_max(unbounded_water_level)
+                            } else {
+                                alt
+                            };
                             // let alt = if !in_river && lake_dist > 0.0 {
                             //     alt.with_max(water_alt + GORGE - river_edge_dist.powf(2.0) / 10.0)
                             // } else {
@@ -1335,6 +1386,7 @@ impl<'a> Sampler<'a> for ColumnGen<'a> {
             cliff_height,
             in_river,
             in_lake: lake_dist <= 0.0,
+            unbounded_water_level,
 
             chunk: sim_chunk,
         })
@@ -1369,6 +1421,7 @@ pub struct ColumnSample<'a> {
     pub cliff_height: f32,
     pub in_river: bool,
     pub in_lake: bool,
+    pub unbounded_water_level: f32,
 
     pub chunk: &'a SimChunk,
 }
diff --git a/world/src/layer/scatter.rs b/world/src/layer/scatter.rs
index 2c905b172f..5d90140600 100644
--- a/world/src/layer/scatter.rs
+++ b/world/src/layer/scatter.rs
@@ -605,7 +605,7 @@ pub fn apply_scatter_to(canvas: &mut Canvas, rng: &mut impl Rng) {
 
     canvas.foreach_col(|canvas, wpos2d, col| {
         // TODO: Why do we need to add 1.0 here? Idk...
-        let underwater = col.alt.floor() < col.water_level.floor();
+        let underwater = col.water_level.floor() > col.alt;
 
         let kind = scatter
             .iter()