add tests
diff --git a/sparse_strips/vello_dev_macros/src/test.rs b/sparse_strips/vello_dev_macros/src/test.rs
index 497b708..44d08b9 100644
--- a/sparse_strips/vello_dev_macros/src/test.rs
+++ b/sparse_strips/vello_dev_macros/src/test.rs
@@ -225,7 +225,7 @@
             let mut ctx = get_ctx::<Scene>(#width, #height, #transparent);
             #input_fn_name(&mut ctx);
             if !#no_ref {
-                check_ref(&ctx, #input_fn_name_str, #webgl_fn_name_str, #hybrid_tolerance, false, RenderMode::OptimizeSpeed, #reference_image_name);
+                check_ref(&ctx, "", #webgl_fn_name_str, #hybrid_tolerance, false, RenderMode::OptimizeSpeed, #reference_image_name);
             }
         }
     };
diff --git a/sparse_strips/vello_sparse_tests/snapshots/scene_larger_than_surface.png b/sparse_strips/vello_sparse_tests/snapshots/scene_larger_than_surface.png
new file mode 100644
index 0000000..183612e
--- /dev/null
+++ b/sparse_strips/vello_sparse_tests/snapshots/scene_larger_than_surface.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:0c84c102a586cdde6dd01c0ab2ed5ac98e75d6fc69b7b2ffad6860944818c4c0
+size 93
diff --git a/sparse_strips/vello_sparse_tests/snapshots/scene_smaller_than_surface.png b/sparse_strips/vello_sparse_tests/snapshots/scene_smaller_than_surface.png
new file mode 100644
index 0000000..c210428
--- /dev/null
+++ b/sparse_strips/vello_sparse_tests/snapshots/scene_smaller_than_surface.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:57ce9fcc9ac98052af7274e3dfd3ac4a93a33594cd962803d80e886ec3a94804
+size 127
diff --git a/sparse_strips/vello_sparse_tests/tests/mod.rs b/sparse_strips/vello_sparse_tests/tests/mod.rs
index 4d9f627..1bd174a 100644
--- a/sparse_strips/vello_sparse_tests/tests/mod.rs
+++ b/sparse_strips/vello_sparse_tests/tests/mod.rs
@@ -36,5 +36,6 @@
 mod mask;
 mod mix;
 mod opacity;
+mod render_size;
 mod renderer;
 mod util;
diff --git a/sparse_strips/vello_sparse_tests/tests/render_size.rs b/sparse_strips/vello_sparse_tests/tests/render_size.rs
new file mode 100644
index 0000000..cf5b4e4
--- /dev/null
+++ b/sparse_strips/vello_sparse_tests/tests/render_size.rs
@@ -0,0 +1,209 @@
+// Copyright 2025 the Vello Authors
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! Tests where the surface dimensions and scene dimensions do not match.
+//!
+//! Note: These tests do not use vello_test proc macro as they test an edge case where the render
+//! surface is a different size than the scene dimensions.
+
+use crate::renderer::Renderer;
+use crate::util::{check_ref_encoded, pixmap_to_png};
+use vello_common::color::palette::css::{LIME, REBECCA_PURPLE};
+use vello_common::kurbo::Rect;
+use vello_common::pixmap::Pixmap;
+use vello_hybrid::Scene;
+
+fn draw_simple_scene(scene: &mut Scene, width: f64, height: f64) {
+    scene.set_paint(LIME.into());
+    // Cover background of scene
+    scene.fill_rect(&Rect::new(0.0, 0.0, width, height));
+
+    scene.set_paint(REBECCA_PURPLE.into());
+    scene.fill_rect(&Rect::new(10., 20., width - 10., height - 20.));
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+#[test]
+fn scene_smaller_than_surface_hybrid() {
+    let scene_width = 50;
+    let scene_height = 50;
+    let surface_width = 80;
+    let surface_height = 80;
+
+    let mut scene = Scene::new(scene_width, scene_height);
+    draw_simple_scene(&mut scene, scene_width as f64, scene_height as f64);
+
+    let mut pixmap = Pixmap::new(surface_width, surface_height);
+
+    scene.render_to_pixmap(&mut pixmap, vello_cpu::RenderMode::OptimizeSpeed);
+    let encoded_image = pixmap_to_png(pixmap, surface_width as u32, surface_height as u32);
+
+    check_ref_encoded(
+        &encoded_image,
+        "scene_smaller_than_surface",
+        "scene_smaller_than_surface_hybrid",
+        1,
+        false,
+        &[],
+    );
+}
+
+#[cfg(all(target_arch = "wasm32", feature = "webgl"))]
+#[wasm_bindgen_test::wasm_bindgen_test]
+async fn scene_smaller_than_surface_hybrid_webgl() {
+    use wasm_bindgen::JsCast;
+    use web_sys::{HtmlCanvasElement, WebGl2RenderingContext};
+
+    let scene_width = 50;
+    let scene_height = 50;
+    let surface_width = 80;
+    let surface_height = 80;
+
+    let mut scene = Scene::new(scene_width, scene_height);
+    draw_simple_scene(&mut scene, scene_width as f64, scene_height as f64);
+
+    let document = web_sys::window().unwrap().document().unwrap();
+    let canvas = document
+        .create_element("canvas")
+        .unwrap()
+        .dyn_into::<HtmlCanvasElement>()
+        .unwrap();
+
+    canvas.set_width(surface_width as u32);
+    canvas.set_height(surface_height as u32);
+
+    // Render the smaller scene to the larger canvas
+    let mut renderer = vello_hybrid::WebGlRenderer::new(&canvas);
+    let render_size = vello_hybrid::RenderSize {
+        width: scene_width as u32,
+        height: scene_height as u32,
+    };
+
+    renderer.render(&scene, &render_size).unwrap();
+
+    let gl = canvas
+        .get_context("webgl2")
+        .unwrap()
+        .unwrap()
+        .dyn_into::<WebGl2RenderingContext>()
+        .unwrap();
+
+    let mut pixels = vec![0_u8; (surface_width as usize) * (surface_height as usize) * 4];
+    gl.read_pixels_with_opt_u8_array(
+        0,
+        0,
+        surface_width.into(),
+        surface_height.into(),
+        WebGl2RenderingContext::RGBA,
+        WebGl2RenderingContext::UNSIGNED_BYTE,
+        Some(&mut pixels),
+    )
+    .unwrap();
+
+    let mut pixmap = Pixmap::new(surface_width, surface_height);
+    pixmap.data_as_u8_slice_mut().copy_from_slice(&pixels);
+
+    let encoded_image = pixmap_to_png(pixmap, surface_width as u32, surface_height as u32);
+
+    check_ref_encoded(
+        &encoded_image,
+        "",
+        "scene_smaller_than_surface_hybrid_webgl",
+        1,
+        false,
+        include_bytes!("../snapshots/scene_smaller_than_surface.png"),
+    );
+}
+
+#[cfg(not(target_arch = "wasm32"))]
+#[test]
+fn scene_larger_than_surface_hybrid() {
+    let scene_width = 80;
+    let scene_height = 80;
+    let surface_width = 50;
+    let surface_height = 50;
+
+    let mut scene = Scene::new(scene_width, scene_height);
+    draw_simple_scene(&mut scene, scene_width as f64, scene_height as f64);
+
+    let mut pixmap = Pixmap::new(surface_width, surface_height);
+
+    scene.render_to_pixmap(&mut pixmap, vello_cpu::RenderMode::OptimizeSpeed);
+    let encoded_image = pixmap_to_png(pixmap, surface_width as u32, surface_height as u32);
+
+    check_ref_encoded(
+        &encoded_image,
+        "scene_larger_than_surface",
+        "scene_larger_than_surface_hybrid",
+        1,
+        false,
+        &[],
+    );
+}
+
+#[cfg(all(target_arch = "wasm32", feature = "webgl"))]
+#[wasm_bindgen_test::wasm_bindgen_test]
+async fn scene_larger_than_surface_hybrid_webgl() {
+    use wasm_bindgen::JsCast;
+    use web_sys::{HtmlCanvasElement, WebGl2RenderingContext};
+
+    let scene_width = 80;
+    let scene_height = 80;
+    let surface_width = 50;
+    let surface_height = 50;
+
+    let mut scene = Scene::new(scene_width, scene_height);
+    draw_simple_scene(&mut scene, scene_width as f64, scene_height as f64);
+
+    let document = web_sys::window().unwrap().document().unwrap();
+    let canvas = document
+        .create_element("canvas")
+        .unwrap()
+        .dyn_into::<HtmlCanvasElement>()
+        .unwrap();
+
+    canvas.set_width(surface_width as u32);
+    canvas.set_height(surface_height as u32);
+
+    // Render the larger scene to the smaller canvas
+    let mut renderer = vello_hybrid::WebGlRenderer::new(&canvas);
+    let render_size = vello_hybrid::RenderSize {
+        width: scene_width as u32,
+        height: scene_height as u32,
+    };
+
+    renderer.render(&scene, &render_size).unwrap();
+
+    let gl = canvas
+        .get_context("webgl2")
+        .unwrap()
+        .unwrap()
+        .dyn_into::<WebGl2RenderingContext>()
+        .unwrap();
+
+    let mut pixels = vec![0_u8; (surface_width as usize) * (surface_height as usize) * 4];
+    gl.read_pixels_with_opt_u8_array(
+        0,
+        0,
+        surface_width.into(),
+        surface_height.into(),
+        WebGl2RenderingContext::RGBA,
+        WebGl2RenderingContext::UNSIGNED_BYTE,
+        Some(&mut pixels),
+    )
+    .unwrap();
+
+    let mut pixmap = Pixmap::new(surface_width, surface_height);
+    pixmap.data_as_u8_slice_mut().copy_from_slice(&pixels);
+
+    let encoded_image = pixmap_to_png(pixmap, surface_width as u32, surface_height as u32);
+
+    check_ref_encoded(
+        &encoded_image,
+        "",
+        "scene_larger_than_surface_hybrid_webgl",
+        1,
+        false,
+        include_bytes!("../snapshots/scene_larger_than_surface.png"),
+    );
+}
diff --git a/sparse_strips/vello_sparse_tests/tests/renderer.rs b/sparse_strips/vello_sparse_tests/tests/renderer.rs
index 64b0072..c0f6644 100644
--- a/sparse_strips/vello_sparse_tests/tests/renderer.rs
+++ b/sparse_strips/vello_sparse_tests/tests/renderer.rs
@@ -236,8 +236,8 @@
             M.lock().unwrap()
         };
 
-        let width = self.width();
-        let height = self.height();
+        let width = pixmap.width();
+        let height = pixmap.height();
 
         // Copied from vello_hybrid/examples/`render_to_file.rs`.
 
@@ -369,8 +369,8 @@
         use wasm_bindgen::JsCast;
         use web_sys::{HtmlCanvasElement, WebGl2RenderingContext};
 
-        let width = self.width();
-        let height = self.height();
+        let width = pixmap.width();
+        let height = pixmap.height();
 
         // Create an offscreen HTMLCanvasElement, render the test image to it, and finally read off
         // the pixmap for diff checking.
diff --git a/sparse_strips/vello_sparse_tests/tests/util.rs b/sparse_strips/vello_sparse_tests/tests/util.rs
index 26d4573..be7374a 100644
--- a/sparse_strips/vello_sparse_tests/tests/util.rs
+++ b/sparse_strips/vello_sparse_tests/tests/util.rs
@@ -230,7 +230,6 @@
     png_data
 }
 
-#[cfg(not(target_arch = "wasm32"))]
 pub(crate) fn check_ref(
     ctx: &impl Renderer,
     // The name of the test.
@@ -242,83 +241,101 @@
     threshold: u8,
     // Whether the test instance is the "gold standard" and should be used
     // for creating reference images.
+    // N.B. Must be `false` on `wasm32` as reference image cannot be written to filesystem.
     is_reference: bool,
     render_mode: RenderMode,
-    _: &[u8],
+    // `ref_data` is the reference image data, passed directly for wasm32.
+    ref_data: &[u8],
 ) {
     let pixmap = render_pixmap(ctx, render_mode);
-
     let encoded_image = pixmap_to_png(pixmap, ctx.width() as u32, ctx.height() as u32);
-    let ref_path = REFS_PATH.join(format!("{}.png", test_name));
 
-    let write_ref_image = || {
-        let optimized =
-            oxipng::optimize_from_memory(&encoded_image, &oxipng::Options::max_compression())
-                .unwrap();
-        std::fs::write(&ref_path, optimized).unwrap();
-    };
-
-    if !ref_path.exists() {
-        if is_reference {
-            write_ref_image();
-            panic!("new reference image was created");
-        } else {
-            panic!("no reference image exists");
-        }
-    }
-
-    let ref_image = load_from_memory(&std::fs::read(&ref_path).unwrap())
-        .unwrap()
-        .into_rgba8();
-    let actual = load_from_memory(&encoded_image).unwrap().into_rgba8();
-
-    let diff_image = get_diff(&ref_image, &actual, threshold);
-
-    if let Some(diff_image) = diff_image {
-        if std::env::var("REPLACE").is_ok() && is_reference {
-            write_ref_image();
-            panic!("test was replaced");
-        }
-
-        if !DIFFS_PATH.exists() {
-            let _ = std::fs::create_dir_all(DIFFS_PATH.as_path());
-        }
-
-        let diff_path = DIFFS_PATH.join(format!("{}.png", specific_name));
-        diff_image
-            .save_with_format(&diff_path, image::ImageFormat::Png)
-            .unwrap();
-
-        panic!("test didnt match reference image");
-    }
+    check_ref_encoded(
+        &encoded_image,
+        test_name,
+        specific_name,
+        threshold,
+        is_reference,
+        ref_data,
+    );
 }
 
-#[cfg(target_arch = "wasm32")]
-pub(crate) fn check_ref(
-    ctx: &impl Renderer,
-    _test_name: &str,
+pub(crate) fn check_ref_encoded(
+    // The encoded image under test.
+    encoded_image: &[u8],
+    // The name of the test.
+    test_name: &str,
     // The name of the specific instance of the test that is being run
     // (e.g. test_gpu, test_cpu_u8, etc.)
     specific_name: &str,
     // Tolerance for pixel differences.
     threshold: u8,
-    // Must be `false` on `wasm32` as reference image cannot be written to filesystem.
+    // Whether the test instance is the "gold standard" and should be used
+    // for creating reference images.
+    // N.B. Must be `false` on `wasm32` as reference image cannot be written to filesystem.
     is_reference: bool,
-    render_mode: RenderMode,
+    // `ref_data` is the reference image data, passed directly for wasm32.
     ref_data: &[u8],
 ) {
-    assert!(!is_reference, "WASM cannot create new reference images");
+    #[cfg(not(target_arch = "wasm32"))]
+    {
+        assert_eq!(ref_data.len(), 0, "ref_data is only used for wasm32 tests");
+        let ref_path = REFS_PATH.join(format!("{}.png", test_name));
 
-    let pixmap = render_pixmap(ctx, render_mode);
-    let encoded_image = pixmap_to_png(pixmap, ctx.width() as u32, ctx.height() as u32);
-    let actual = load_from_memory(&encoded_image).unwrap().into_rgba8();
+        let write_ref_image = || {
+            let optimized =
+                oxipng::optimize_from_memory(&encoded_image, &oxipng::Options::max_compression())
+                    .unwrap();
+            std::fs::write(&ref_path, optimized).unwrap();
+        };
 
-    let ref_image = load_from_memory(ref_data).unwrap().into_rgba8();
+        if !ref_path.exists() {
+            if is_reference {
+                write_ref_image();
+                panic!("new reference image was created");
+            } else {
+                panic!("no reference image exists");
+            }
+        }
 
-    let diff_image = get_diff(&ref_image, &actual, threshold);
-    if let Some(ref img) = diff_image {
-        append_diff_image_to_browser_document(specific_name, img);
-        panic!("test didn't match reference image. Scroll to bottom of browser to view diff.");
+        let ref_image = load_from_memory(&std::fs::read(&ref_path).unwrap())
+            .unwrap()
+            .into_rgba8();
+        let actual = load_from_memory(&encoded_image).unwrap().into_rgba8();
+
+        let diff_image = get_diff(&ref_image, &actual, threshold);
+
+        if let Some(diff_image) = diff_image {
+            if std::env::var("REPLACE").is_ok() && is_reference {
+                write_ref_image();
+                panic!("test was replaced");
+            }
+
+            if !DIFFS_PATH.exists() {
+                let _ = std::fs::create_dir_all(DIFFS_PATH.as_path());
+            }
+
+            let diff_path = DIFFS_PATH.join(format!("{}.png", specific_name));
+            diff_image
+                .save_with_format(&diff_path, image::ImageFormat::Png)
+                .unwrap();
+
+            panic!("test didnt match reference image");
+        }
+    }
+    #[cfg(target_arch = "wasm32")]
+    {
+        assert!(!is_reference, "WASM cannot create new reference images");
+        assert_eq!(test_name.len(), 0, "test_name is not used in wasm32 tests");
+        let actual = load_from_memory(&encoded_image).unwrap().into_rgba8();
+
+        let ref_image = load_from_memory(ref_data).unwrap().into_rgba8();
+
+        let diff_image = get_diff(&ref_image, &actual, threshold);
+        if let Some(ref img) = diff_image {
+            append_diff_image_to_browser_document(specific_name, img);
+            panic!("test didn't match reference image. Scroll to bottom of browser to view diff.");
+        }
     }
 }