.
diff --git a/sparse_strips/vello_hybrid/Cargo.toml b/sparse_strips/vello_hybrid/Cargo.toml
index 4e99eaf..eef9ff5 100644
--- a/sparse_strips/vello_hybrid/Cargo.toml
+++ b/sparse_strips/vello_hybrid/Cargo.toml
@@ -47,8 +47,8 @@
 roxmltree = "0.20.0"
 
 [features]
-default = ["wgpu", "wgpu_default", "text"]
-std = ["wgpu", "vello_common/std", "glifo?/std"]
+default = ["std", "wgpu", "wgpu_default", "text"]
+std = ["vello_common/std", "glifo?/std"]
 libm = ["vello_common/libm", "glifo?/libm"]
 wgpu = ["dep:wgpu", "dep:vello_sparse_shaders"]
 # Enable wgpu with its default features. If you need to customise the set of enabled wgpu features,
diff --git a/sparse_strips/vello_hybrid/README.md b/sparse_strips/vello_hybrid/README.md
index 596156e..2c51fe8 100644
--- a/sparse_strips/vello_hybrid/README.md
+++ b/sparse_strips/vello_hybrid/README.md
@@ -39,6 +39,7 @@
 
 ## Feature Flags
 
+- `std` (enabled by default): Enables standard library support.
 - `wgpu` (enabled by default): Enables the GPU rendering backend via wgpu and includes the required sparse shaders.
 - `wgpu_default` (enabled by default): Enables wgpu with its default hardware backends (such as Vulkan, Metal, and DX12).
 - `text` (enabled by default): Enables glyph rendering ([`Scene::glyph_run`]).
diff --git a/sparse_strips/vello_hybrid/src/lib.rs b/sparse_strips/vello_hybrid/src/lib.rs
index 82a0f55..92c630f 100644
--- a/sparse_strips/vello_hybrid/src/lib.rs
+++ b/sparse_strips/vello_hybrid/src/lib.rs
@@ -22,6 +22,7 @@
 //!
 //! # Feature Flags
 //!
+//! - `std` (enabled by default): Enables standard library support.
 //! - `wgpu` (enabled by default): Enables the GPU rendering backend via wgpu and includes the required sparse shaders.
 //! - `wgpu_default` (enabled by default): Enables wgpu with its default hardware backends (such as Vulkan, Metal, and DX12).
 //! - `text` (enabled by default): Enables glyph rendering ([`Scene::glyph_run`]).
@@ -45,8 +46,11 @@
 
 extern crate alloc;
 
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 pub(crate) mod filter;
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 mod gradient_cache;
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 mod render;
 mod resources;
 mod sampling;
@@ -60,6 +64,7 @@
 
 #[cfg(feature = "wgpu")]
 pub use render::{AtlasWriter, RenderTargetConfig, Renderer, TextureBindings};
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 pub use render::{Config, GpuStrip, RenderSize};
 #[cfg(all(feature = "webgl", feature = "probe"))]
 pub use render::{Probe, ProbeResult};
diff --git a/sparse_strips/vello_hybrid/src/resources.rs b/sparse_strips/vello_hybrid/src/resources.rs
index 5a17ce5..037a7ab 100644
--- a/sparse_strips/vello_hybrid/src/resources.rs
+++ b/sparse_strips/vello_hybrid/src/resources.rs
@@ -3,7 +3,7 @@
 
 //! Persistent renderer resources shared across frames.
 
-#[cfg(feature = "text")]
+#[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
 use crate::text::GlyphAtlasResources;
 #[cfg(feature = "text")]
 use glifo::GlyphPrepCache;
@@ -13,10 +13,17 @@
 /// Persistent resources required by Vello Hybrid for rendering.
 #[derive(Debug)]
 pub struct Resources {
+    #[cfg_attr(
+        not(any(feature = "webgl", feature = "wgpu")),
+        expect(
+            dead_code,
+            reason = "this is used by renderer backends, which may be disabled"
+        )
+    )]
     pub(crate) image_cache: ImageCache,
     #[cfg(feature = "text")]
     pub(crate) glyph_prep_cache: GlyphPrepCache,
-    #[cfg(feature = "text")]
+    #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
     pub(crate) glyph_resources: Option<GlyphAtlasResources>,
 }
 
@@ -28,7 +35,7 @@
             #[cfg(feature = "text")]
             glyph_prep_cache: GlyphPrepCache::default(),
             // Will be initialized lazily.
-            #[cfg(feature = "text")]
+            #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
             glyph_resources: None,
         }
     }
diff --git a/sparse_strips/vello_hybrid/src/scene.rs b/sparse_strips/vello_hybrid/src/scene.rs
index 0546893..be6bdb4 100644
--- a/sparse_strips/vello_hybrid/src/scene.rs
+++ b/sparse_strips/vello_hybrid/src/scene.rs
@@ -1156,16 +1156,16 @@
 #[cfg(test)]
 mod tests {
     use super::*;
-    #[cfg(feature = "text")]
+    #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
     use crate::resources::Resources;
-    #[cfg(feature = "text")]
+    #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
     use alloc::sync::Arc;
     use core::f64::consts::PI;
-    #[cfg(feature = "text")]
+    #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
     use glifo::Glyph;
     use vello_common::kurbo::{Affine, Point, Rect};
     use vello_common::peniko::Color;
-    #[cfg(feature = "text")]
+    #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
     use vello_common::peniko::{Blob, FontData};
 
     // These tests serve the purpose of ensuring that the logic for selecting fast paths
@@ -1249,7 +1249,7 @@
         assert!(is_rect(&cmds[2]));
     }
 
-    #[cfg(feature = "text")]
+    #[cfg(all(feature = "text", any(feature = "webgl", feature = "wgpu")))]
     #[test]
     fn glyph_atlas_resources_are_lazy() {
         const ROBOTO_FONT: &[u8] =
diff --git a/sparse_strips/vello_hybrid/src/text.rs b/sparse_strips/vello_hybrid/src/text.rs
index 360e098..d2591bc 100644
--- a/sparse_strips/vello_hybrid/src/text.rs
+++ b/sparse_strips/vello_hybrid/src/text.rs
@@ -12,28 +12,34 @@
 
 use core::ops::RangeInclusive;
 
-use crate::{AtlasId, Resources, Scene};
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
+use crate::AtlasId;
+use crate::{Resources, Scene};
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 use glifo::atlas::{PendingBitmapUpload, PendingClearRect};
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 use glifo::renderer::replay_atlas_commands;
-use glifo::{
-    AtlasCacher, AtlasSlot, DrawSink, GLYPH_PADDING, Glyph, GlyphAtlas, GlyphCacheConfig,
-    GlyphRunBackend, ImageCache,
-};
+use glifo::{AtlasCacher, AtlasSlot, DrawSink, GLYPH_PADDING, Glyph, GlyphRunBackend};
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
+use glifo::{GlyphAtlas, GlyphCacheConfig, ImageCache};
 use peniko::BlendMode;
 use peniko::color::palette::css::BLACK;
 use peniko::color::{AlphaColor, Srgb};
 use vello_common::kurbo::{Affine, BezPath, Rect};
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 use vello_common::multi_atlas::AtlasConfig;
 use vello_common::paint::{Image, ImageSource, PaintType};
 use vello_common::peniko;
 
 /// Glyph atlas cache for the hybrid (GPU) renderer.
 #[derive(Debug)]
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 pub(crate) struct GlyphAtlasResources {
     pub(crate) glyph_atlas: GlyphAtlas,
     pub(crate) glyph_renderer: Scene,
 }
 
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 impl GlyphAtlasResources {
     pub(crate) fn with_config(
         atlas_width: u16,
@@ -51,6 +57,7 @@
     }
 }
 
+#[cfg(any(feature = "webgl", feature = "wgpu"))]
 impl Resources {
     fn ensure_glyph_resources(&mut self) {
         if self.glyph_resources.is_none() {
@@ -217,16 +224,23 @@
         Glyphs: Iterator<Item = Glyph> + Clone,
     {
         let atlas_cacher = if self.atlas_cache_enabled {
-            self.resources.ensure_glyph_resources();
-            let glyph_resources = self
-                .resources
-                .glyph_resources
-                .as_mut()
-                .expect("glyph atlas resources must exist after initialization");
-            AtlasCacher::Enabled(
-                &mut glyph_resources.glyph_atlas,
-                &mut self.resources.image_cache,
-            )
+            #[cfg(any(feature = "webgl", feature = "wgpu"))]
+            {
+                self.resources.ensure_glyph_resources();
+                let glyph_resources = self
+                    .resources
+                    .glyph_resources
+                    .as_mut()
+                    .expect("glyph atlas resources must exist after initialization");
+                AtlasCacher::Enabled(
+                    &mut glyph_resources.glyph_atlas,
+                    &mut self.resources.image_cache,
+                )
+            }
+            #[cfg(not(any(feature = "webgl", feature = "wgpu")))]
+            {
+                AtlasCacher::Disabled
+            }
         } else {
             AtlasCacher::Disabled
         };
diff --git a/sparse_strips/vello_hybrid/src/util.rs b/sparse_strips/vello_hybrid/src/util.rs
index d659e11..0ad8c04 100644
--- a/sparse_strips/vello_hybrid/src/util.rs
+++ b/sparse_strips/vello_hybrid/src/util.rs
@@ -111,6 +111,7 @@
 }
 
 impl IntRect {
+    #[cfg(any(feature = "webgl", feature = "wgpu"))]
     pub(crate) fn new(offset: impl Into<IntOffset>, size: impl Into<IntSize>) -> Self {
         Self {
             offset: offset.into(),