diff --git a/Cargo.lock b/Cargo.lock
index eabf8f21a2c61afafdae87a9e8bb3c7170e209ec..f2937f67313778f3c029ab74c6d0aa2964d2453b 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2978,9 +2978,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73"
+checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -2988,9 +2988,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb"
+checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
 dependencies = [
  "bumpalo",
  "log",
@@ -3015,9 +3015,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258"
+checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -3025,9 +3025,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
+checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3038,9 +3038,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.86"
+version = "0.2.87"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93"
+checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
 
 [[package]]
 name = "wayland-scanner"
diff --git a/Cargo.toml b/Cargo.toml
index 7dac19dd83b5ddbb18a7aae2272848fc34414f96..2e3e890e9d54223c121cff91fceb2c0507dc62d0 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -39,7 +39,7 @@ js-sys = "0.3.61"
 insta = "1.29.0"
 
 [[example]]
-name = "basic_button"
+name = "basic_ui"
 
 [[example]]
 name = "basic_sprite"
diff --git a/examples/basic_button.rs b/examples/basic_button.rs
deleted file mode 100644
index 9f355754c3ca76f4aab8a7e1081b0a6207781a1a..0000000000000000000000000000000000000000
--- a/examples/basic_button.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use bevy::{prelude::*, window::PrimaryWindow};
-use bevy_cosmic_edit::{
-    create_cosmic_font_system, spawn_cosmic_edit, ActiveEditor, CosmicEditMeta, CosmicEditPlugin,
-    CosmicFont, CosmicFontConfig, CosmicMetrics, CosmicNode, CosmicText, CosmicTextPos,
-};
-use cosmic_text::AttrsOwned;
-
-fn setup(
-    mut commands: Commands,
-    windows: Query<&Window, With<PrimaryWindow>>,
-    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
-) {
-    let primary_window = windows.single();
-    commands.spawn(Camera2dBundle::default());
-    let root = commands
-        .spawn(NodeBundle {
-            style: Style {
-                display: Display::Flex,
-                width: Val::Percent(100.),
-                height: Val::Percent(100.),
-                ..default()
-            },
-            ..default()
-        })
-        .id();
-
-    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
-    let cosmic_font_config = CosmicFontConfig {
-        fonts_dir_path: None,
-        font_bytes: Some(vec![font_bytes]),
-        load_system_fonts: true,
-    };
-    let font_system = create_cosmic_font_system(cosmic_font_config);
-    let font_system_handle: Handle<CosmicFont> = cosmic_fonts.add(CosmicFont(font_system));
-    let mut attrs = cosmic_text::Attrs::new();
-    attrs = attrs.family(cosmic_text::Family::Name("Victor Mono"));
-    attrs = attrs.color(cosmic_text::Color::rgb(0x94, 0x00, 0xD3));
-    let cosmic_edit_meta = CosmicEditMeta {
-        text: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        bg: Color::WHITE,
-        metrics: CosmicMetrics {
-            font_size: 14.,
-            line_height: 18.,
-            scale_factor: primary_window.scale_factor() as f32,
-        },
-        font_system_handle,
-        node: CosmicNode::Ui,
-        size: None,
-        readonly: false,
-        bg_image: None,
-    };
-    let cosmic_edit = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
-    commands.entity(root).add_child(cosmic_edit);
-    commands.insert_resource(ActiveEditor {
-        entity: Some(cosmic_edit),
-    });
-}
-
-fn main() {
-    App::new()
-        .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin)
-        .add_systems(Startup, setup)
-        .run();
-}
diff --git a/examples/basic_sprite.rs b/examples/basic_sprite.rs
index 696d26c810385be49ade2148d75ff3506e419ad6..ef0b9e3ca5113029f525bd62995bf7bc12c05e5d 100644
--- a/examples/basic_sprite.rs
+++ b/examples/basic_sprite.rs
@@ -1,15 +1,14 @@
 use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow};
 use bevy_cosmic_edit::{
-    create_cosmic_font_system, spawn_cosmic_edit, ActiveEditor, CosmicEditMeta, CosmicEditPlugin,
-    CosmicEditSprite, CosmicFont, CosmicFontConfig, CosmicMetrics, CosmicNode, CosmicText,
-    CosmicTextPos,
+    ActiveEditor, CosmicAttrs, CosmicEditPlugin, CosmicEditSpriteBundle, CosmicFontConfig,
+    CosmicFontSystem, CosmicMetrics, CosmicText, CosmicTextPosition,
 };
 use cosmic_text::AttrsOwned;
 
 fn setup(
     mut commands: Commands,
     windows: Query<&Window, With<PrimaryWindow>>,
-    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     let primary_window = windows.single();
     let camera_bundle = Camera2dBundle {
@@ -19,49 +18,51 @@ fn setup(
         ..default()
     };
     commands.spawn(camera_bundle);
-    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
-    let cosmic_font_config = CosmicFontConfig {
-        fonts_dir_path: None,
-        font_bytes: Some(vec![font_bytes]),
-        load_system_fonts: true,
-    };
-    let font_system = create_cosmic_font_system(cosmic_font_config);
-    let font_system_handle: Handle<CosmicFont> = cosmic_fonts.add(CosmicFont(font_system));
+
     let mut attrs = cosmic_text::Attrs::new();
     attrs = attrs.family(cosmic_text::Family::Name("Victor Mono"));
     attrs = attrs.color(cosmic_text::Color::rgb(0x94, 0x00, 0xD3));
+
     let scale_factor = primary_window.scale_factor() as f32;
-    let cosmic_edit_meta = CosmicEditMeta {
-        text: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        bg: Color::WHITE,
-        metrics: CosmicMetrics {
+
+    let cosmic_edit = CosmicEditSpriteBundle {
+        sprite: Sprite {
+            custom_size: Some(Vec2::new(primary_window.width(), primary_window.height())),
+            ..default()
+        },
+        cosmic_metrics: CosmicMetrics {
             font_size: 14.,
             line_height: 18.,
             scale_factor,
         },
-        font_system_handle,
-        node: CosmicNode::Sprite(CosmicEditSprite {
-            transform: Transform {
-                translation: Vec3::new(0., 0., 1.),
-                ..default()
-            },
-        }),
-        size: Some((primary_window.width(), primary_window.height())),
-        readonly: false,
-        bg_image: None,
-    };
-    let cosmic_edit = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
+        text_position: CosmicTextPosition::Center,
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+        ..default()
+    }
+    .set_text(
+        CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
+        AttrsOwned::new(attrs),
+        &mut font_system.0,
+    );
+
+    let cosmic_edit = commands.spawn(cosmic_edit).id();
+
     commands.insert_resource(ActiveEditor {
         entity: Some(cosmic_edit),
     });
 }
 
 fn main() {
+    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
+    let font_config = CosmicFontConfig {
+        fonts_dir_path: None,
+        font_bytes: Some(vec![font_bytes]),
+        load_system_fonts: true,
+    };
+
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin)
+        .add_plugins(CosmicEditPlugin { font_config })
         .add_systems(Startup, setup)
         .run();
 }
diff --git a/examples/basic_ui.rs b/examples/basic_ui.rs
new file mode 100644
index 0000000000000000000000000000000000000000..943700dd1abca1bc417a3f021c13d958160ef09c
--- /dev/null
+++ b/examples/basic_ui.rs
@@ -0,0 +1,69 @@
+use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow};
+use bevy_cosmic_edit::{
+    ActiveEditor, CosmicAttrs, CosmicEditPlugin, CosmicEditUiBundle, CosmicFontConfig,
+    CosmicFontSystem, CosmicMetrics, CosmicText, CosmicTextPosition,
+};
+use cosmic_text::AttrsOwned;
+
+fn setup(
+    mut commands: Commands,
+    windows: Query<&Window, With<PrimaryWindow>>,
+    mut font_system: ResMut<CosmicFontSystem>,
+) {
+    let primary_window = windows.single();
+    let camera_bundle = Camera2dBundle {
+        camera_2d: Camera2d {
+            clear_color: ClearColorConfig::Custom(Color::WHITE),
+        },
+        ..default()
+    };
+    commands.spawn(camera_bundle);
+
+    let mut attrs = cosmic_text::Attrs::new();
+    attrs = attrs.family(cosmic_text::Family::Name("Victor Mono"));
+    attrs = attrs.color(cosmic_text::Color::rgb(0x94, 0x00, 0xD3));
+
+    let scale_factor = primary_window.scale_factor() as f32;
+
+    let cosmic_edit = CosmicEditUiBundle {
+        style: Style {
+            width: Val::Percent(100.),
+            height: Val::Percent(100.),
+            ..default()
+        },
+        cosmic_metrics: CosmicMetrics {
+            font_size: 14.,
+            line_height: 18.,
+            scale_factor,
+        },
+        text_position: CosmicTextPosition::Center,
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+        ..default()
+    }
+    .set_text(
+        CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
+        AttrsOwned::new(attrs),
+        &mut font_system.0,
+    );
+
+    let cosmic_edit = commands.spawn(cosmic_edit).id();
+
+    commands.insert_resource(ActiveEditor {
+        entity: Some(cosmic_edit),
+    });
+}
+
+fn main() {
+    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
+    let font_config = CosmicFontConfig {
+        fonts_dir_path: None,
+        font_bytes: Some(vec![font_bytes]),
+        load_system_fonts: true,
+    };
+
+    App::new()
+        .add_plugins(DefaultPlugins)
+        .add_plugins(CosmicEditPlugin { font_config })
+        .add_systems(Startup, setup)
+        .run();
+}
diff --git a/examples/bevy_api_testing.rs b/examples/bevy_api_testing.rs
new file mode 100644
index 0000000000000000000000000000000000000000..fcb9bc8f0abac266939ecf841e7671c7db8654d7
--- /dev/null
+++ b/examples/bevy_api_testing.rs
@@ -0,0 +1,49 @@
+use bevy::prelude::*;
+use bevy_cosmic_edit::{
+    change_active_editor_sprite, change_active_editor_ui, ActiveEditor, CosmicEditPlugin,
+    CosmicEditSpriteBundle, CosmicEditUiBundle,
+};
+
+fn setup(mut commands: Commands) {
+    commands.spawn(Camera2dBundle::default());
+
+    // spawn a new CosmicEditBundle
+    commands.spawn(CosmicEditUiBundle {
+        style: Style {
+            // Size and position of text box
+            width: Val::Px(300.),
+            height: Val::Px(50.),
+            left: Val::Px(100.),
+            top: Val::Px(100.),
+            ..default()
+        },
+        ..default()
+    });
+
+    let sprite_editor = commands
+        .spawn(CosmicEditSpriteBundle {
+            sprite: Sprite {
+                // Sets size of text box
+                custom_size: Some(Vec2::new(300., 100.)),
+                ..default()
+            },
+            // Position of text box
+            transform: Transform::from_xyz(100., 200., 0.),
+            ..default()
+        })
+        .id();
+
+    commands.insert_resource(ActiveEditor {
+        entity: Some(sprite_editor),
+    });
+}
+
+fn main() {
+    App::new()
+        .add_plugins(DefaultPlugins)
+        .add_plugins(CosmicEditPlugin::default())
+        .add_systems(Startup, setup)
+        .add_systems(Update, change_active_editor_ui)
+        .add_systems(Update, change_active_editor_sprite)
+        .run();
+}
diff --git a/examples/font_per_widget.rs b/examples/font_per_widget.rs
index 8cfd85eb5b4e907c792e8488b8f49ae55d53c9f6..50d0843d14160b3d9d57981b18dd49eec0439a10 100644
--- a/examples/font_per_widget.rs
+++ b/examples/font_per_widget.rs
@@ -1,15 +1,18 @@
+#![allow(clippy::type_complexity)]
+
 use bevy::{prelude::*, window::PrimaryWindow};
+use bevy_cosmic_edit::change_active_editor_sprite;
+use bevy_cosmic_edit::change_active_editor_ui;
 use bevy_cosmic_edit::{
-    create_cosmic_font_system, get_cosmic_text, spawn_cosmic_edit, ActiveEditor, CosmicEdit,
-    CosmicEditMeta, CosmicEditPlugin, CosmicFont, CosmicFontConfig, CosmicMetrics, CosmicNode,
-    CosmicText, CosmicTextPos,
+    ActiveEditor, CosmicAttrs, CosmicEditPlugin, CosmicEditUiBundle, CosmicFontConfig,
+    CosmicFontSystem, CosmicMetrics, CosmicText, CosmicTextPosition,
 };
-use cosmic_text::*;
+use cosmic_text::{Attrs, AttrsOwned, Family};
 
 fn setup(
     mut commands: Commands,
     windows: Query<&Window, With<PrimaryWindow>>,
-    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     commands.spawn(Camera2dBundle::default());
     let root = commands
@@ -24,13 +27,6 @@ fn setup(
         })
         .id();
     let primary_window = windows.single();
-    let cosmic_font_config = CosmicFontConfig {
-        fonts_dir_path: None,
-        font_bytes: None,
-        load_system_fonts: true,
-    };
-    let font_system = create_cosmic_font_system(cosmic_font_config);
-    let font_system_handle = cosmic_fonts.add(CosmicFont(font_system));
 
     let attrs = Attrs::new();
     let serif_attrs = attrs.family(Family::Serif);
@@ -229,77 +225,76 @@ fn setup(
         )],
     ];
 
-    let cosmic_edit_meta_1 = CosmicEditMeta {
-        text: CosmicText::MultiStyle(lines),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        metrics: CosmicMetrics {
+    let cosmic_edit_1 = CosmicEditUiBundle {
+        text_position: bevy_cosmic_edit::CosmicTextPosition::Center,
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+        cosmic_metrics: CosmicMetrics {
             font_size: 18.,
             line_height: 22.,
             scale_factor: primary_window.scale_factor() as f32,
         },
-        font_system_handle: font_system_handle.clone(),
-        node: CosmicNode::Ui,
-        size: None,
-        bg: bevy::prelude::Color::WHITE,
-        readonly: false,
-        bg_image: None,
-    };
-    let cosmic_edit_1 = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta_1);
+        style: Style {
+            width: Val::Percent(50.),
+            height: Val::Percent(100.),
+            ..default()
+        },
+        background_color: BackgroundColor(Color::WHITE),
+        ..default()
+    }
+    .set_text(
+        CosmicText::MultiStyle(lines),
+        AttrsOwned::new(attrs),
+        &mut font_system.0,
+    );
 
     let mut attrs_2 = cosmic_text::Attrs::new();
     attrs_2 = attrs_2.family(cosmic_text::Family::Name("Times New Roman"));
-    let cosmic_edit_meta_2 = CosmicEditMeta {
-        text: CosmicText::OneStyle("Widget 2.\nClick on me =>".to_string()),
-        attrs: AttrsOwned::new(attrs_2),
-        metrics: CosmicMetrics {
+
+    let cosmic_edit_2 = CosmicEditUiBundle {
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs_2)),
+        cosmic_metrics: CosmicMetrics {
             font_size: 14.,
             line_height: 18.,
             scale_factor: primary_window.scale_factor() as f32,
         },
-        font_system_handle: font_system_handle.clone(),
-        node: CosmicNode::Ui,
-        text_pos: CosmicTextPos::Center,
-        size: None,
-        bg: bevy::prelude::Color::WHITE.with_a(0.8),
-        readonly: false,
-        bg_image: None,
-    };
-    let cosmic_edit_2 = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta_2);
-
-    commands.entity(root).add_child(cosmic_edit_1);
-    commands.entity(root).add_child(cosmic_edit_2);
+        text_position: CosmicTextPosition::Center,
+        background_color: BackgroundColor(Color::WHITE.with_a(0.8)),
+        style: Style {
+            width: Val::Percent(50.),
+            height: Val::Percent(100.),
+            ..default()
+        },
+        ..default()
+    }
+    .set_text(
+        CosmicText::OneStyle("Widget 2.\nClick on me =>".to_string()),
+        AttrsOwned::new(attrs_2),
+        &mut font_system.0,
+    );
 
-    commands.insert_resource(ActiveEditor {
-        entity: Some(cosmic_edit_1),
+    let mut id = None;
+    // Spawn the CosmicEditUiBundles as children of root
+    commands.entity(root).with_children(|parent| {
+        id = Some(parent.spawn(cosmic_edit_1).id());
+        parent.spawn(cosmic_edit_2);
     });
-}
 
-fn change_active_editor(
-    mut commands: Commands,
-    mut interaction_query: Query<
-        (&Interaction, &mut CosmicEdit, Entity),
-        (Changed<Interaction>, With<CosmicEdit>),
-    >,
-) {
-    for (interaction, cosmic_edit, entity) in interaction_query.iter_mut() {
-        if let Interaction::Pressed = interaction {
-            commands.insert_resource(ActiveEditor {
-                entity: Some(entity),
-            });
-            info!(
-                "Widget text: {}",
-                get_cosmic_text(&cosmic_edit.editor.buffer())
-            );
-        }
-    }
+    // Set active editor
+    commands.insert_resource(ActiveEditor { entity: id });
 }
 
 fn main() {
+    let font_config = CosmicFontConfig {
+        fonts_dir_path: None,
+        font_bytes: None,
+        load_system_fonts: true,
+    };
+
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin)
+        .add_plugins(CosmicEditPlugin { font_config })
         .add_systems(Startup, setup)
-        .add_systems(Update, change_active_editor)
+        .add_systems(Update, change_active_editor_ui)
+        .add_systems(Update, change_active_editor_sprite)
         .run();
 }
diff --git a/examples/multiple_sprites.rs b/examples/multiple_sprites.rs
index e89bd86255da132a08f9942adefef741cf97c588..d71e6b5860fd5f6f7bdc762183dab7da544ed4c5 100644
--- a/examples/multiple_sprites.rs
+++ b/examples/multiple_sprites.rs
@@ -1,18 +1,16 @@
 use bevy::{core_pipeline::clear_color::ClearColorConfig, prelude::*, window::PrimaryWindow};
+use bevy_cosmic_edit::change_active_editor_sprite;
+use bevy_cosmic_edit::change_active_editor_ui;
 use bevy_cosmic_edit::{
-    create_cosmic_font_system, spawn_cosmic_edit, ActiveEditor, CosmicEdit, CosmicEditMeta,
-    CosmicEditPlugin, CosmicEditSprite, CosmicFont, CosmicFontConfig, CosmicMetrics, CosmicNode,
-    CosmicText, CosmicTextPos,
+    ActiveEditor, CosmicAttrs, CosmicEditPlugin, CosmicEditSpriteBundle, CosmicFontConfig,
+    CosmicFontSystem, CosmicMetrics, CosmicText, CosmicTextPosition,
 };
 use cosmic_text::AttrsOwned;
 
-#[derive(Component)]
-pub struct MainCamera;
-
 fn setup(
     mut commands: Commands,
     windows: Query<&Window, With<PrimaryWindow>>,
-    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     let primary_window = windows.single();
     let camera_bundle = Camera2dBundle {
@@ -21,15 +19,8 @@ fn setup(
         },
         ..default()
     };
-    commands.spawn((camera_bundle, MainCamera));
-    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
-    let cosmic_font_config = CosmicFontConfig {
-        fonts_dir_path: None,
-        font_bytes: Some(vec![font_bytes]),
-        load_system_fonts: true,
-    };
-    let font_system = create_cosmic_font_system(cosmic_font_config);
-    let font_system_handle = cosmic_fonts.add(CosmicFont(font_system));
+    commands.spawn(camera_bundle);
+
     let mut attrs = cosmic_text::Attrs::new();
     attrs = attrs.family(cosmic_text::Family::Name("Victor Mono"));
     attrs = attrs.color(cosmic_text::Color::rgb(0x94, 0x00, 0xD3));
@@ -38,111 +29,73 @@ fn setup(
         line_height: 18.,
         scale_factor: primary_window.scale_factor() as f32,
     };
-    let cosmic_edit_meta = CosmicEditMeta {
-        text: CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        metrics: metrics.clone(),
-        font_system_handle: font_system_handle.clone(),
-        node: CosmicNode::Sprite(CosmicEditSprite {
-            transform: Transform {
-                translation: Vec3::new(-primary_window.width() / 4., 0., 1.),
-                ..default()
-            },
-        }),
-        size: Some((primary_window.width() / 2., primary_window.height())),
-        bg: Color::WHITE,
-        readonly: false,
-        bg_image: None,
-    };
-    let cosmic_edit_1 = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
-    let cosmic_edit_meta = CosmicEditMeta {
-        text: CosmicText::OneStyle("Widget_2. Click on me".to_string()),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        metrics: metrics.clone(),
-        font_system_handle: font_system_handle.clone(),
-        node: CosmicNode::Sprite(CosmicEditSprite {
-            transform: Transform {
-                translation: Vec3::new(
-                    primary_window.width() / 4.,
-                    -primary_window.height() / 4.,
-                    1.,
-                ),
-                ..default()
-            },
-        }),
-        size: Some((primary_window.width() / 2., primary_window.height() / 2.)),
-        bg: Color::GRAY.with_a(0.5),
-        readonly: false,
-        bg_image: None,
-    };
-    let _ = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
-    let cosmic_edit_meta = CosmicEditMeta {
-        text: CosmicText::OneStyle("Widget_3. Click on me".to_string()),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        metrics: metrics.clone(),
-        font_system_handle: font_system_handle.clone(),
-        node: CosmicNode::Sprite(CosmicEditSprite {
-            transform: Transform {
-                translation: Vec3::new(
-                    primary_window.width() / 4.,
-                    primary_window.height() / 4.,
-                    1.,
-                ),
-                ..default()
-            },
-        }),
-        size: Some((primary_window.width() / 2., primary_window.height() / 2.)),
-        bg: Color::GRAY.with_a(0.8),
-        readonly: false,
-        bg_image: None,
-    };
-    let _ = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
-    commands.insert_resource(ActiveEditor {
-        entity: Some(cosmic_edit_1),
-    });
-}
 
-fn change_active_editor(
-    mut commands: Commands,
-    windows: Query<&Window, With<PrimaryWindow>>,
-    buttons: Res<Input<MouseButton>>,
-    mut cosmic_edit_query: Query<(&mut CosmicEdit, &GlobalTransform, Entity), With<CosmicEdit>>,
-    camera_q: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
-) {
-    let window = windows.single();
-    let (camera, camera_transform) = camera_q.single();
-    if buttons.just_pressed(MouseButton::Left) {
-        for (cosmic_edit, node_transform, entity) in &mut cosmic_edit_query.iter_mut() {
-            let size = (cosmic_edit.width, cosmic_edit.height);
-            let x_min = node_transform.affine().translation.x - size.0 / 2.;
-            let y_min = node_transform.affine().translation.y - size.1 / 2.;
-            let x_max = node_transform.affine().translation.x + size.0 / 2.;
-            let y_max = node_transform.affine().translation.y + size.1 / 2.;
-            window.cursor_position().and_then(|pos| {
-                if let Some(pos) = camera.viewport_to_world_2d(camera_transform, pos) {
-                    Some({
-                        if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max {
-                            commands.insert_resource(ActiveEditor {
-                                entity: Some(entity),
-                            });
-                        };
-                    })
-                } else {
-                    None
-                }
-            });
-        }
+    let cosmic_edit_1 = CosmicEditSpriteBundle {
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+        cosmic_metrics: metrics.clone(),
+        sprite: Sprite {
+            custom_size: Some(Vec2 {
+                x: primary_window.width() / 2.,
+                y: primary_window.height(),
+            }),
+            ..default()
+        },
+        transform: Transform::from_translation(Vec3::new(-primary_window.width() / 4., 0., 1.)),
+        text_position: CosmicTextPosition::Center,
+        background_color: BackgroundColor(Color::ALICE_BLUE),
+        ..default()
     }
+    .set_text(
+        CosmicText::OneStyle("馃榾馃榾馃榾 x => y".to_string()),
+        AttrsOwned::new(attrs),
+        &mut font_system.0,
+    );
+
+    let cosmic_edit_2 = CosmicEditSpriteBundle {
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+        cosmic_metrics: metrics,
+        sprite: Sprite {
+            custom_size: Some(Vec2 {
+                x: primary_window.width() / 2.,
+                y: primary_window.height() / 2.,
+            }),
+            ..default()
+        },
+        transform: Transform::from_translation(Vec3::new(
+            primary_window.width() / 4.,
+            -primary_window.height() / 4.,
+            1.,
+        )),
+        text_position: CosmicTextPosition::Center,
+        background_color: BackgroundColor(Color::GRAY.with_a(0.5)),
+        ..default()
+    }
+    .set_text(
+        CosmicText::OneStyle("Widget_2. Click on me".to_string()),
+        AttrsOwned::new(attrs),
+        &mut font_system.0,
+    );
+
+    let id = commands.spawn(cosmic_edit_1).id();
+
+    commands.insert_resource(ActiveEditor { entity: Some(id) });
+
+    commands.spawn(cosmic_edit_2);
 }
 
 fn main() {
+    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
+    let font_config = CosmicFontConfig {
+        fonts_dir_path: None,
+        font_bytes: Some(vec![font_bytes]),
+        load_system_fonts: true,
+    };
+
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin)
+        .add_plugins(CosmicEditPlugin { font_config })
         .add_systems(Startup, setup)
-        .add_systems(Update, change_active_editor)
+        .add_systems(Update, change_active_editor_ui)
+        .add_systems(Update, change_active_editor_sprite)
         .run();
 }
diff --git a/examples/readonly.rs b/examples/readonly.rs
index 7a9a79a40a55aa0a28ebec14165035dc5114471a..049d0431538cbb9aae633559d2838bd04c06b32c 100644
--- a/examples/readonly.rs
+++ b/examples/readonly.rs
@@ -1,14 +1,14 @@
 use bevy::{prelude::*, window::PrimaryWindow};
 use bevy_cosmic_edit::{
-    create_cosmic_font_system, spawn_cosmic_edit, ActiveEditor, CosmicEditMeta, CosmicEditPlugin,
-    CosmicFont, CosmicFontConfig, CosmicMetrics, CosmicNode, CosmicText, CosmicTextPos,
+    ActiveEditor, CosmicAttrs, CosmicEditPlugin, CosmicEditUiBundle, CosmicFontConfig,
+    CosmicFontSystem, CosmicMetrics, CosmicText, CosmicTextPosition, ReadOnly,
 };
 use cosmic_text::AttrsOwned;
 
 fn setup(
     mut commands: Commands,
     windows: Query<&Window, With<PrimaryWindow>>,
-    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     let primary_window = windows.single();
     commands.spawn(Camera2dBundle::default());
@@ -23,45 +23,54 @@ fn setup(
             ..default()
         })
         .id();
-    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
-    let cosmic_font_config = CosmicFontConfig {
-        fonts_dir_path: None,
-        font_bytes: Some(vec![font_bytes]),
-        load_system_fonts: true,
-    };
 
-    let font_system = create_cosmic_font_system(cosmic_font_config);
-    let font_system_handle = cosmic_fonts.add(CosmicFont(font_system));
     let mut attrs = cosmic_text::Attrs::new();
     attrs = attrs.family(cosmic_text::Family::Name("Victor Mono"));
     attrs = attrs.color(cosmic_text::Color::rgb(0x94, 0x00, 0xD3));
-    let cosmic_edit_meta = CosmicEditMeta {
-        text: CosmicText::OneStyle("馃榾馃榾馃榾 x => y\nRead only widget".to_string()),
-        attrs: AttrsOwned::new(attrs),
-        text_pos: CosmicTextPos::Center,
-        bg: Color::WHITE,
-        metrics: CosmicMetrics {
+
+    let cosmic_edit = CosmicEditUiBundle {
+        style: Style {
+            width: Val::Percent(100.),
+            height: Val::Percent(100.),
+            ..default()
+        },
+        cosmic_attrs: CosmicAttrs(AttrsOwned::new(attrs)),
+        text_position: CosmicTextPosition::Center,
+        background_color: BackgroundColor(Color::WHITE),
+        cosmic_metrics: CosmicMetrics {
             font_size: 14.,
             line_height: 18.,
             scale_factor: primary_window.scale_factor() as f32,
         },
-        font_system_handle,
-        node: CosmicNode::Ui,
-        size: None,
-        readonly: true,
-        bg_image: None,
-    };
-    let cosmic_edit = spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
-    commands.entity(root).add_child(cosmic_edit);
-    commands.insert_resource(ActiveEditor {
-        entity: Some(cosmic_edit),
+        ..default()
+    }
+    .set_text(
+        CosmicText::OneStyle("馃榾馃榾馃榾 x => y\nRead only widget".to_string()),
+        AttrsOwned::new(attrs),
+        &mut font_system.0,
+    );
+
+    let mut id = None;
+    // Spawn the CosmicEditUiBundle as a child of root
+    commands.entity(root).with_children(|parent| {
+        id = Some(parent.spawn(cosmic_edit).insert(ReadOnly).id());
     });
+
+    // Set active editor
+    commands.insert_resource(ActiveEditor { entity: id });
 }
 
 fn main() {
+    let font_bytes: &[u8] = include_bytes!("../assets/fonts/VictorMono-Regular.ttf");
+    let font_config = CosmicFontConfig {
+        fonts_dir_path: None,
+        font_bytes: Some(vec![font_bytes]),
+        load_system_fonts: true,
+    };
+
     App::new()
         .add_plugins(DefaultPlugins)
-        .add_plugins(CosmicEditPlugin)
+        .add_plugins(CosmicEditPlugin { font_config })
         .add_systems(Startup, setup)
         .run();
 }
diff --git a/src/lib.rs b/src/lib.rs
index 0c6bfb853f9ff75a63ecc5019be74572b2b83747..164865c3e40d4b753a54e5db081766746a1a76f4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,3 +1,5 @@
+#![allow(clippy::type_complexity)]
+
 use std::{collections::VecDeque, path::PathBuf, time::Duration};
 #[path = "utils.rs"]
 pub mod utils;
@@ -7,63 +9,351 @@ use bevy::{
     asset::HandleId,
     input::mouse::{MouseScrollUnit, MouseWheel},
     prelude::*,
-    reflect::{TypePath, TypeUuid},
-    render::render_resource::Extent3d,
+    render::{render_resource::Extent3d, texture::DEFAULT_IMAGE_HANDLE},
+    ui::FocusPolicy,
     window::{PrimaryWindow, WindowScaleFactorChanged},
 };
 use cosmic_text::{
-    Action, AttrsList, AttrsOwned, Buffer, BufferLine, Cursor, Edit, Editor, FontSystem, Metrics,
-    Shaping, SwashCache,
+    Action, Attrs, AttrsList, AttrsOwned, Buffer, BufferLine, Cursor, Edit, Editor, FontSystem,
+    Metrics, Shaping, SwashCache,
 };
 use image::{imageops::FilterType, GenericImageView};
 
-#[derive(Clone)]
-pub struct CosmicEditUi;
-
-#[derive(Clone)]
-pub struct CosmicEditSprite {
-    pub transform: Transform,
-}
-
-#[derive(Clone)]
-pub enum CosmicNode {
-    Ui,
-    Sprite(CosmicEditSprite),
-}
-
 #[derive(Clone)]
 pub enum CosmicText {
     OneStyle(String),
-    MultiStyle(Vec<Vec<(String, cosmic_text::AttrsOwned)>>),
+    MultiStyle(Vec<Vec<(String, AttrsOwned)>>),
 }
 
-#[derive(Clone)]
+/// Enum representing the position of the cosmic text.
+#[derive(Clone, Component, Default)]
+pub enum CosmicTextPosition {
+    #[default]
+    Center,
+    TopLeft,
+}
+
+#[derive(Clone, Component)]
 pub struct CosmicMetrics {
     pub font_size: f32,
     pub line_height: f32,
     pub scale_factor: f32,
 }
 
-/// Contains metadata for spawning cosmic edit, including text content, position, size, and style.
-#[derive(Clone)]
-pub struct CosmicEditMeta {
-    pub text: CosmicText,
-    pub text_pos: CosmicTextPos,
-    pub attrs: cosmic_text::AttrsOwned,
-    pub metrics: CosmicMetrics,
-    pub font_system_handle: Handle<CosmicFont>,
-    pub size: Option<(f32, f32)>, // None used for bevy-ui nodes to use parent size
-    pub node: CosmicNode,
-    pub bg: bevy::prelude::Color,
-    pub bg_image: Option<Handle<Image>>,
-    pub readonly: bool,
+impl Default for CosmicMetrics {
+    fn default() -> Self {
+        Self {
+            font_size: 12.,
+            line_height: 12.,
+            scale_factor: 1.,
+        }
+    }
 }
 
-/// Enum representing the position of the cosmic text.
-#[derive(Clone)]
-pub enum CosmicTextPos {
-    Center,
-    TopLeft,
+#[derive(Resource)]
+pub struct CosmicFontSystem(pub FontSystem);
+
+#[derive(Component)]
+pub struct ReadOnly; // tag component
+
+#[derive(Component)]
+pub struct CosmicEditor(pub Editor);
+
+impl Default for CosmicEditor {
+    fn default() -> Self {
+        Self(Editor::new(Buffer::new_empty(Metrics::new(12., 14.))))
+    }
+}
+
+impl CosmicEditor {
+    pub fn set_text(
+        &mut self,
+        text: CosmicText,
+        attrs: AttrsOwned,
+        // i'd like to get the font system + attrs automagically but i'm too 3head -bytemunch
+        font_system: &mut FontSystem,
+    ) -> &mut Self {
+        let editor = &mut self.0;
+        editor.buffer_mut().lines.clear();
+        match text {
+            CosmicText::OneStyle(text) => {
+                editor.buffer_mut().set_text(
+                    font_system,
+                    text.as_str(),
+                    attrs.as_attrs(),
+                    Shaping::Advanced,
+                );
+            }
+            CosmicText::MultiStyle(lines) => {
+                for line in lines {
+                    let mut line_text = String::new();
+                    let mut attrs_list = AttrsList::new(attrs.as_attrs());
+                    for (text, attrs) in line.iter() {
+                        let start = line_text.len();
+                        line_text.push_str(text);
+                        let end = line_text.len();
+                        attrs_list.add_span(start..end, attrs.as_attrs());
+                    }
+                    editor.buffer_mut().lines.push(BufferLine::new(
+                        line_text,
+                        attrs_list,
+                        Shaping::Advanced,
+                    ));
+                }
+            }
+        }
+        self
+    }
+
+    /// Retrieves the cosmic text content from an editor.
+    ///
+    /// # Arguments
+    ///
+    /// * none, takes the rust magic ref to self
+    ///
+    /// # Returns
+    ///
+    /// A `String` containing the cosmic text content.
+    pub fn get_text(&self) -> String {
+        let buffer = self.0.buffer();
+        let mut text = String::new();
+        let line_count = buffer.lines.len();
+
+        for (i, line) in buffer.lines.iter().enumerate() {
+            text.push_str(line.text());
+
+            if i < line_count - 1 {
+                text.push('\n');
+            }
+        }
+
+        text
+    }
+}
+
+/// Adds the font system to each editor when added
+fn cosmic_editor_builder(
+    mut added_editors: Query<
+        (
+            &mut CosmicEditor,
+            &CosmicAttrs,
+            &CosmicMetrics,
+            &BackgroundColor,
+            Option<&ReadOnly>,
+            Option<&Node>,
+            Option<&Sprite>,
+        ),
+        Added<CosmicEditor>,
+    >,
+    mut font_system: ResMut<CosmicFontSystem>,
+) {
+    for (mut editor, attrs, metrics, background_color, readonly, node, sprite) in
+        added_editors.iter_mut()
+    {
+        // keep old text if set
+        let mut text = editor.get_text();
+
+        if text.is_empty() {
+            text = "".into();
+            editor.0.buffer_mut().set_text(
+                &mut font_system.0,
+                text.as_str(),
+                attrs.0.as_attrs(),
+                Shaping::Advanced,
+            );
+        }
+
+        editor.0.buffer_mut().set_metrics(
+            &mut font_system.0,
+            Metrics::new(metrics.font_size, metrics.line_height).scale(metrics.scale_factor),
+        );
+
+        if let Some(node) = node {
+            editor
+                .0
+                .buffer_mut()
+                .set_size(&mut font_system.0, node.size().x, node.size().y)
+        }
+
+        if let Some(sprite) = sprite {
+            if let Some(size) = sprite.custom_size {
+                editor
+                    .0
+                    .buffer_mut()
+                    .set_size(&mut font_system.0, size.x, size.y)
+            }
+        }
+
+        // hide cursor on readonly buffers
+        let mut cursor = editor.0.cursor();
+        if readonly.is_some() {
+            cursor.color = Some(bevy_color_to_cosmic(background_color.0));
+        }
+        editor.0.set_cursor(cursor);
+    }
+}
+
+#[derive(Component)]
+pub struct CosmicAttrs(pub AttrsOwned);
+
+impl Default for CosmicAttrs {
+    fn default() -> Self {
+        CosmicAttrs(AttrsOwned::new(Attrs::new()))
+    }
+}
+
+#[derive(Component, Default)]
+pub struct CosmicBackground(pub Option<Handle<Image>>);
+
+#[derive(Bundle)]
+pub struct CosmicEditUiBundle {
+    // Bevy UI bits
+    /// Describes the logical size of the node
+    pub node: Node,
+    /// Marker component that signals this node is a button
+    pub button: Button,
+    /// Styles which control the layout (size and position) of the node and it's children
+    /// In some cases these styles also affect how the node drawn/painted.
+    pub style: Style,
+    /// Describes whether and how the button has been interacted with by the input
+    pub interaction: Interaction,
+    /// Whether this node should block interaction with lower nodes
+    pub focus_policy: FocusPolicy,
+    /// The background color, which serves as a "fill" for this node
+    pub background_color: BackgroundColor,
+    /// The color of the Node's border
+    pub border_color: BorderColor,
+    /// This is used as the cosmic text canvas
+    pub image: UiImage,
+    /// The transform of the node
+    ///
+    /// This field is automatically managed by the UI layout system.
+    /// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
+    pub transform: Transform,
+    /// The global transform of the node
+    ///
+    /// This field is automatically managed by the UI layout system.
+    /// To alter the position of the `NodeBundle`, use the properties of the [`Style`] component.
+    pub global_transform: GlobalTransform,
+    /// Describes the visibility properties of the node
+    pub visibility: Visibility,
+    /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
+    pub computed_visibility: ComputedVisibility,
+    /// Indicates the depth at which the node should appear in the UI
+    pub z_index: ZIndex,
+    // cosmic bits
+    /// cosmic-text Editor, holds the text buffer + font system
+    pub editor: CosmicEditor,
+    /// text positioning enum
+    pub text_position: CosmicTextPosition,
+    /// text metrics
+    pub cosmic_metrics: CosmicMetrics,
+    /// edit history
+    pub cosmic_edit_history: CosmicEditHistory,
+    /// text attributes
+    pub cosmic_attrs: CosmicAttrs,
+    /// bg img
+    pub background_image: CosmicBackground,
+}
+
+impl CosmicEditUiBundle {
+    pub fn set_text(
+        mut self,
+        text: CosmicText,
+        attrs: AttrsOwned,
+        font_system: &mut FontSystem,
+    ) -> Self {
+        self.editor.set_text(text, attrs, font_system);
+        self
+    }
+}
+
+impl Default for CosmicEditUiBundle {
+    fn default() -> Self {
+        Self {
+            focus_policy: FocusPolicy::Block,
+            node: Default::default(),
+            button: Default::default(),
+            style: Default::default(),
+            border_color: BorderColor(Color::NONE),
+            interaction: Default::default(),
+            background_color: Default::default(),
+            image: Default::default(),
+            transform: Default::default(),
+            global_transform: Default::default(),
+            visibility: Default::default(),
+            computed_visibility: Default::default(),
+            z_index: Default::default(),
+            editor: Default::default(),
+            text_position: Default::default(),
+            cosmic_metrics: Default::default(),
+            cosmic_edit_history: Default::default(),
+            cosmic_attrs: Default::default(),
+            background_image: Default::default(),
+        }
+    }
+}
+
+#[derive(Bundle)]
+pub struct CosmicEditSpriteBundle {
+    // Bevy Sprite Bits
+    pub sprite: Sprite,
+    pub transform: Transform,
+    pub global_transform: GlobalTransform,
+    pub texture: Handle<Image>,
+    /// User indication of whether an entity is visible
+    pub visibility: Visibility,
+    /// Algorithmically-computed indication of whether an entity is visible and should be extracted for rendering
+    pub computed_visibility: ComputedVisibility,
+    //
+    pub background_color: BackgroundColor,
+    // cosmic bits
+    /// cosmic-text Editor, holds the text buffer + font system
+    pub editor: CosmicEditor,
+    /// text positioning enum
+    pub text_position: CosmicTextPosition,
+    /// text metrics
+    pub cosmic_metrics: CosmicMetrics,
+    /// edit history
+    pub cosmic_edit_history: CosmicEditHistory,
+    /// text attributes
+    pub cosmic_attrs: CosmicAttrs,
+    /// bg img
+    pub background_image: CosmicBackground,
+}
+
+impl CosmicEditSpriteBundle {
+    pub fn set_text(
+        mut self,
+        text: CosmicText,
+        attrs: AttrsOwned,
+        font_system: &mut FontSystem,
+    ) -> Self {
+        self.editor.set_text(text, attrs, font_system);
+        self
+    }
+}
+
+impl Default for CosmicEditSpriteBundle {
+    fn default() -> Self {
+        Self {
+            sprite: Default::default(),
+            transform: Default::default(),
+            global_transform: Default::default(),
+            texture: DEFAULT_IMAGE_HANDLE.typed(),
+            visibility: Visibility::Hidden,
+            computed_visibility: Default::default(),
+            //
+            background_color: Default::default(),
+            //
+            editor: Default::default(),
+            text_position: Default::default(),
+            cosmic_metrics: Default::default(),
+            cosmic_edit_history: Default::default(),
+            cosmic_attrs: Default::default(),
+            background_image: Default::default(),
+        }
+    }
 }
 
 #[derive(Clone)]
@@ -72,54 +362,41 @@ pub struct EditHistoryItem {
     pub lines: Vec<Vec<(String, AttrsOwned)>>,
 }
 
-#[derive(Component)]
+#[derive(Component, Default)]
 pub struct CosmicEditHistory {
     pub edits: VecDeque<EditHistoryItem>,
     pub current_edit: usize,
 }
 
-#[derive(Component)]
-pub struct CosmicEdit {
-    pub editor: Editor,
-    pub font_system: Handle<CosmicFont>,
-    pub attrs: cosmic_text::AttrsOwned,
-    pub text_pos: CosmicTextPos,
-    pub bg: bevy::prelude::Color,
-    pub bg_image: Option<Handle<Image>>,
-    pub width: f32,
-    pub height: f32,
-    pub font_size: f32,
-    pub line_height: f32,
-    pub readonly: bool,
-    pub is_ui_node: bool,
-}
-
-#[derive(TypeUuid, TypePath)]
-#[uuid = "DC6A0357-7941-4ADE-9332-24EA87E38961"]
-pub struct CosmicFont(pub FontSystem);
-
 /// Plugin struct that adds systems and initializes resources related to cosmic edit functionality.
-pub struct CosmicEditPlugin;
+#[derive(Default)]
+pub struct CosmicEditPlugin {
+    pub font_config: CosmicFontConfig,
+}
 
 impl Plugin for CosmicEditPlugin {
     fn build(&self, app: &mut App) {
-        app.add_systems(
-            Update,
-            (
-                cosmic_edit_bevy_events,
-                cosmic_edit_set_redraw,
-                on_scale_factor_change,
-                cosmic_edit_redraw_buffer_ui
-                    .before(cosmic_edit_set_redraw)
-                    .before(on_scale_factor_change),
-                cosmic_edit_redraw_buffer.before(on_scale_factor_change),
-            ),
-        )
-        .init_resource::<ActiveEditor>()
-        .add_asset::<CosmicFont>()
-        .insert_resource(SwashCacheState {
-            swash_cache: SwashCache::new(),
-        });
+        let font_system = create_cosmic_font_system(self.font_config.clone());
+
+        app.add_systems(PreUpdate, cosmic_editor_builder)
+            .add_systems(
+                Update,
+                (
+                    cosmic_edit_bevy_events,
+                    cosmic_edit_set_redraw,
+                    on_scale_factor_change,
+                    cosmic_edit_redraw_buffer_ui
+                        .before(cosmic_edit_set_redraw)
+                        .before(on_scale_factor_change),
+                    cosmic_edit_redraw_buffer.before(on_scale_factor_change),
+                ),
+            )
+            .init_resource::<ActiveEditor>()
+            // .add_asset::<CosmicFont>()
+            .insert_resource(SwashCacheState {
+                swash_cache: SwashCache::new(),
+            })
+            .insert_resource(CosmicFontSystem(font_system));
     }
 }
 
@@ -130,19 +407,29 @@ pub struct ActiveEditor {
 }
 
 /// Resource struct that holds configuration options for cosmic fonts.
-#[derive(Resource, Default)]
+#[derive(Resource, Clone)]
 pub struct CosmicFontConfig {
     pub fonts_dir_path: Option<PathBuf>,
     pub font_bytes: Option<Vec<&'static [u8]>>,
     pub load_system_fonts: bool, // caution: this can be relatively slow
 }
 
+impl Default for CosmicFontConfig {
+    fn default() -> Self {
+        Self {
+            load_system_fonts: true,
+            font_bytes: None,
+            fonts_dir_path: None,
+        }
+    }
+}
+
 #[derive(Resource)]
 struct SwashCacheState {
     swash_cache: SwashCache,
 }
 
-pub fn create_cosmic_font_system(cosmic_font_config: CosmicFontConfig) -> FontSystem {
+fn create_cosmic_font_system(cosmic_font_config: CosmicFontConfig) -> FontSystem {
     let locale = sys_locale::get_locale().unwrap_or_else(|| String::from("en-US"));
     let mut db = cosmic_text::fontdb::Database::new();
     if let Some(dir_path) = cosmic_font_config.fonts_dir_path.clone() {
@@ -161,22 +448,18 @@ pub fn create_cosmic_font_system(cosmic_font_config: CosmicFontConfig) -> FontSy
 
 fn on_scale_factor_change(
     mut scale_factor_changed: EventReader<WindowScaleFactorChanged>,
-    mut cosmic_edit_query: Query<&mut CosmicEdit, With<CosmicEdit>>,
-    mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
+    mut cosmic_query: Query<(&mut CosmicEditor, &mut CosmicMetrics)>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     if !scale_factor_changed.is_empty() {
         let new_scale_factor = scale_factor_changed.iter().last().unwrap().scale_factor as f32;
-        for mut cosmic_edit in &mut cosmic_edit_query.iter_mut() {
-            if let Some(font_system) = cosmic_fonts.get_mut(&cosmic_edit.font_system) {
-                let font_system = &mut font_system.0;
-                let metrics = Metrics::new(cosmic_edit.font_size, cosmic_edit.line_height)
-                    .scale(new_scale_factor);
-                cosmic_edit
-                    .editor
-                    .buffer_mut()
-                    .set_metrics(font_system, metrics);
-                cosmic_edit.editor.buffer_mut().set_redraw(true);
-            }
+        for (mut editor, metrics) in &mut cosmic_query.iter_mut() {
+            let font_system = &mut font_system.0;
+            let metrics =
+                Metrics::new(metrics.font_size, metrics.line_height).scale(new_scale_factor);
+
+            editor.0.buffer_mut().set_metrics(font_system, metrics);
+            editor.0.buffer_mut().set_redraw(true);
         }
     }
 }
@@ -217,30 +500,7 @@ pub fn get_node_cursor_pos(
     })
 }
 
-/// Retrieves the cosmic text content from an editor.
-///
-/// # Arguments
-///
-/// * `editor` - A reference to the `Editor` instance containing the text content.
-///
-/// # Returns
-///
-/// A `String` containing the cosmic text content.
-pub fn get_cosmic_text(buffer: &Buffer) -> String {
-    let mut text = String::new();
-    let line_count = buffer.lines.len();
-
-    for (i, line) in buffer.lines.iter().enumerate() {
-        text.push_str(line.text());
-
-        if i < line_count - 1 {
-            text.push('\n');
-        }
-    }
-
-    text
-}
-
+/// Returns texts from a MultiStyle buffer
 pub fn get_text_spans(
     buffer: &Buffer,
     default_attrs: AttrsOwned,
@@ -279,9 +539,13 @@ pub fn get_text_spans(
     spans
 }
 
-fn save_edit_history(cosmic_edit: &mut CosmicEdit, edit_history: &mut CosmicEditHistory) {
+fn save_edit_history(
+    editor: &mut Editor,
+    attrs: &AttrsOwned,
+    edit_history: &mut CosmicEditHistory,
+) {
     let edits = &edit_history.edits;
-    let current_lines = get_text_spans(cosmic_edit.editor.buffer(), cosmic_edit.attrs.clone());
+    let current_lines = get_text_spans(editor.buffer(), attrs.clone());
     let current_edit = edit_history.current_edit;
     let mut new_edits = VecDeque::new();
     new_edits.extend(edits.iter().take(current_edit + 1).cloned());
@@ -290,7 +554,7 @@ fn save_edit_history(cosmic_edit: &mut CosmicEdit, edit_history: &mut CosmicEdit
         new_edits.drain(0..100);
     }
     new_edits.push_back(EditHistoryItem {
-        cursor: cosmic_edit.editor.cursor(),
+        cursor: editor.cursor(),
         lines: current_lines,
     });
     let len = new_edits.len();
@@ -300,7 +564,7 @@ fn save_edit_history(cosmic_edit: &mut CosmicEdit, edit_history: &mut CosmicEdit
     };
 }
 
-fn bevy_color_to_cosmic(color: bevy::prelude::Color) -> cosmic_text::Color {
+pub fn bevy_color_to_cosmic(color: bevy::prelude::Color) -> cosmic_text::Color {
     cosmic_text::Color::rgba(
         (color.r() * 255.) as u8,
         (color.g() * 255.) as u8,
@@ -328,6 +592,8 @@ pub fn get_x_offset(buffer: &Buffer) -> i32 {
     ((buffer.size().0 - text_width) / 2.0) as i32
 }
 
+#[allow(clippy::too_many_arguments, clippy::type_complexity)]
+// the meat of the input management
 pub fn cosmic_edit_bevy_events(
     windows: Query<&Window, With<PrimaryWindow>>,
     active_editor: Res<ActiveEditor>,
@@ -336,15 +602,20 @@ pub fn cosmic_edit_bevy_events(
     buttons: Res<Input<MouseButton>>,
     mut cosmic_edit_query: Query<
         (
-            &mut CosmicEdit,
+            &mut CosmicEditor,
             &mut CosmicEditHistory,
             &GlobalTransform,
+            &CosmicAttrs,
+            &CosmicTextPosition,
             Entity,
         ),
-        With<CosmicEdit>,
+        With<CosmicEditor>,
     >,
+    readonly_query: Query<&ReadOnly>,
+    node_query: Query<&mut Node>,
+    sprite_query: Query<&mut Sprite>,
+    mut font_system: ResMut<CosmicFontSystem>,
     mut is_deleting: Local<bool>,
-    mut font_system_assets: ResMut<Assets<CosmicFont>>,
     mut scroll_evr: EventReader<MouseWheel>,
     mut edits_duration: Local<Option<Duration>>,
     mut undoredo_duration: Local<Option<Duration>>,
@@ -353,437 +624,396 @@ pub fn cosmic_edit_bevy_events(
     let primary_window = windows.single();
     let scale_factor = primary_window.scale_factor() as f32;
     let (camera, camera_transform) = camera_q.iter().find(|(c, _)| c.is_active).unwrap();
-    for (mut cosmic_edit, mut edit_history, node_transform, entity) in
+    for (mut editor, mut edit_history, node_transform, attrs, text_position, entity) in
         &mut cosmic_edit_query.iter_mut()
     {
+        let readonly = readonly_query.get(entity).is_ok();
+
+        let (width, height, is_ui_node) = match node_query.get(entity) {
+            Ok(node) => (node.size().x, node.size().y, true),
+            Err(_) => {
+                let sprite = sprite_query.get(entity).unwrap();
+                let size = sprite.custom_size.unwrap();
+                (size.x, size.y, false)
+            }
+        };
+
+        let editor = &mut editor.0;
+        let attrs = &attrs.0;
+
         if active_editor.entity == Some(entity) {
-            if let Some(font_system) = font_system_assets.get_mut(&cosmic_edit.font_system) {
-                let now_ms = get_timestamp();
+            let now_ms = get_timestamp();
 
-                #[cfg(target_os = "macos")]
-                let command = keys.any_pressed([KeyCode::SuperLeft, KeyCode::SuperRight]);
+            #[cfg(target_os = "macos")]
+            let command = keys.any_pressed([KeyCode::SuperLeft, KeyCode::SuperRight]);
 
-                #[cfg(not(target_os = "macos"))]
-                let command = keys.any_pressed([KeyCode::ControlLeft, KeyCode::ControlRight]);
+            #[cfg(not(target_os = "macos"))]
+            let command = keys.any_pressed([KeyCode::ControlLeft, KeyCode::ControlRight]);
 
-                let shift = keys.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight]);
+            let shift = keys.any_pressed([KeyCode::ShiftLeft, KeyCode::ShiftRight]);
 
-                #[cfg(target_os = "macos")]
-                let option = keys.any_pressed([KeyCode::AltLeft, KeyCode::AltRight]);
+            #[cfg(target_os = "macos")]
+            let option = keys.any_pressed([KeyCode::AltLeft, KeyCode::AltRight]);
 
-                // if shift key is pressed
-                let already_has_selection = cosmic_edit.editor.select_opt().is_some();
-                if shift && !already_has_selection {
-                    let cursor = cosmic_edit.editor.cursor();
-                    cosmic_edit.editor.set_select_opt(Some(cursor));
-                }
+            // if shift key is pressed
+            let already_has_selection = editor.select_opt().is_some();
+            if shift && !already_has_selection {
+                let cursor = editor.cursor();
+                editor.set_select_opt(Some(cursor));
+            }
 
-                #[cfg(target_os = "macos")]
-                let should_jump = command && option;
-                #[cfg(not(target_os = "macos"))]
-                let should_jump = command;
-
-                if should_jump && keys.just_pressed(KeyCode::Left) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::PreviousWord);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+            #[cfg(target_os = "macos")]
+            let should_jump = command && option;
+            #[cfg(not(target_os = "macos"))]
+            let should_jump = command;
+
+            if should_jump && keys.just_pressed(KeyCode::Left) {
+                editor.action(&mut font_system.0, Action::PreviousWord);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if should_jump && keys.just_pressed(KeyCode::Right) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::NextWord);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if should_jump && keys.just_pressed(KeyCode::Right) {
+                editor.action(&mut font_system.0, Action::NextWord);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if should_jump && keys.just_pressed(KeyCode::Home) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::BufferStart);
-                    // there's a bug with cosmic text where it doesn't update the visual cursor for this action
-                    // TODO: fix upstream
-                    cosmic_edit.editor.buffer_mut().set_redraw(true);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if should_jump && keys.just_pressed(KeyCode::Home) {
+                editor.action(&mut font_system.0, Action::BufferStart);
+                // there's a bug with cosmic text where it doesn't update the visual cursor for this action
+                // TODO: fix upstream
+                editor.buffer_mut().set_redraw(true);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if should_jump && keys.just_pressed(KeyCode::End) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::BufferEnd);
-                    // there's a bug with cosmic text where it doesn't update the visual cursor for this action
-                    // TODO: fix upstream
-                    cosmic_edit.editor.buffer_mut().set_redraw(true);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if should_jump && keys.just_pressed(KeyCode::End) {
+                editor.action(&mut font_system.0, Action::BufferEnd);
+                // there's a bug with cosmic text where it doesn't update the visual cursor for this action
+                // TODO: fix upstream
+                editor.buffer_mut().set_redraw(true);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
+                return;
+            }
 
-                if keys.just_pressed(KeyCode::Left) {
-                    cosmic_edit.editor.action(&mut font_system.0, Action::Left);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+            if keys.just_pressed(KeyCode::Left) {
+                editor.action(&mut font_system.0, Action::Left);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if keys.just_pressed(KeyCode::Right) {
-                    cosmic_edit.editor.action(&mut font_system.0, Action::Right);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if keys.just_pressed(KeyCode::Right) {
+                editor.action(&mut font_system.0, Action::Right);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if keys.just_pressed(KeyCode::Up) {
-                    cosmic_edit.editor.action(&mut font_system.0, Action::Up);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if keys.just_pressed(KeyCode::Up) {
+                editor.action(&mut font_system.0, Action::Up);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if keys.just_pressed(KeyCode::Down) {
-                    cosmic_edit.editor.action(&mut font_system.0, Action::Down);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if keys.just_pressed(KeyCode::Down) {
+                editor.action(&mut font_system.0, Action::Down);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if !cosmic_edit.readonly && keys.just_pressed(KeyCode::Back) {
-                    #[cfg(target_arch = "wasm32")]
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::Backspace);
-                    *is_deleting = true;
+                return;
+            }
+
+            if !readonly && keys.just_pressed(KeyCode::Back) {
+                #[cfg(target_arch = "wasm32")]
+                editor.action(&mut font_system.0, Action::Backspace);
+                *is_deleting = true;
+            }
+            if !readonly && keys.just_released(KeyCode::Back) {
+                *is_deleting = false;
+            }
+            if !readonly && keys.just_pressed(KeyCode::Delete) {
+                editor.action(&mut font_system.0, Action::Delete);
+            }
+            if keys.just_pressed(KeyCode::Escape) {
+                editor.action(&mut font_system.0, Action::Escape);
+            }
+            if command && keys.just_pressed(KeyCode::A) {
+                editor.action(&mut font_system.0, Action::BufferEnd);
+                let current_cursor = editor.cursor();
+                editor.set_select_opt(Some(Cursor {
+                    line: 0,
+                    index: 0,
+                    affinity: current_cursor.affinity,
+                    color: current_cursor.color,
+                }));
+                return;
+            }
+            if keys.just_pressed(KeyCode::Home) {
+                editor.action(&mut font_system.0, Action::Home);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if !cosmic_edit.readonly && keys.just_released(KeyCode::Back) {
-                    *is_deleting = false;
+                return;
+            }
+            if keys.just_pressed(KeyCode::End) {
+                editor.action(&mut font_system.0, Action::End);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if !cosmic_edit.readonly && keys.just_pressed(KeyCode::Delete) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::Delete);
+                return;
+            }
+            if keys.just_pressed(KeyCode::PageUp) {
+                editor.action(&mut font_system.0, Action::PageUp);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if keys.just_pressed(KeyCode::Escape) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::Escape);
+                return;
+            }
+            if keys.just_pressed(KeyCode::PageDown) {
+                editor.action(&mut font_system.0, Action::PageDown);
+                if !shift {
+                    editor.set_select_opt(None);
                 }
-                if command && keys.just_pressed(KeyCode::A) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::BufferEnd);
-                    let current_cursor = cosmic_edit.editor.cursor();
-                    cosmic_edit.editor.set_select_opt(Some(Cursor {
-                        line: 0,
-                        index: 0,
-                        affinity: current_cursor.affinity,
-                        color: current_cursor.color,
-                    }));
-                    // RETURN
+                return;
+            }
+
+            // redo
+            #[cfg(not(target_os = "windows"))]
+            let requested_redo = command && shift && keys.just_pressed(KeyCode::Z);
+            #[cfg(target_os = "windows")]
+            let requested_redo = command && keys.just_pressed(KeyCode::Y);
+
+            if !readonly && requested_redo {
+                let edits = &edit_history.edits;
+                if edits.is_empty() {
                     return;
                 }
-                if keys.just_pressed(KeyCode::Home) {
-                    cosmic_edit.editor.action(&mut font_system.0, Action::Home);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
+                if edit_history.current_edit == edits.len() - 1 {
                     return;
                 }
-                if keys.just_pressed(KeyCode::End) {
-                    cosmic_edit.editor.action(&mut font_system.0, Action::End);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
+                let idx = edit_history.current_edit + 1;
+                if let Some(current_edit) = edits.get(idx) {
+                    editor.buffer_mut().lines.clear();
+                    for line in current_edit.lines.iter() {
+                        let mut line_text = String::new();
+                        let mut attrs_list = AttrsList::new(attrs.as_attrs());
+                        for (text, attrs) in line.iter() {
+                            let start = line_text.len();
+                            line_text.push_str(text);
+                            let end = line_text.len();
+                            attrs_list.add_span(start..end, attrs.as_attrs());
+                        }
+                        editor.buffer_mut().lines.push(BufferLine::new(
+                            line_text,
+                            attrs_list,
+                            Shaping::Advanced,
+                        ));
                     }
-                    // RETURN
-                    return;
+                    editor.set_cursor(current_edit.cursor);
+                    editor.buffer_mut().set_redraw(true);
+                    edit_history.current_edit += 1;
                 }
-                if keys.just_pressed(KeyCode::PageUp) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::PageUp);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
+                *undoredo_duration = Some(Duration::from_millis(now_ms as u64));
+                return;
+            }
+            // undo
+            let requested_undo = command && keys.just_pressed(KeyCode::Z);
+
+            if !readonly && requested_undo {
+                let edits = &edit_history.edits;
+                if edits.is_empty() {
                     return;
                 }
-                if keys.just_pressed(KeyCode::PageDown) {
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::PageDown);
-                    if !shift {
-                        cosmic_edit.editor.set_select_opt(None);
-                    }
-                    // RETURN
+                if edit_history.current_edit <= 1 {
                     return;
                 }
-
-                // redo
-                #[cfg(not(target_os = "windows"))]
-                let requested_redo = command && shift && keys.just_pressed(KeyCode::Z);
-                #[cfg(target_os = "windows")]
-                let requested_redo = command && keys.just_pressed(KeyCode::Y);
-
-                if !cosmic_edit.readonly && requested_redo {
-                    let edits = &edit_history.edits;
-                    if edits.is_empty() {
-                        // RETURN
-                        return;
-                    }
-                    if edit_history.current_edit == edits.len() - 1 {
-                        // RETURN
-                        return;
-                    }
-                    let idx = edit_history.current_edit + 1;
-                    if let Some(current_edit) = edits.get(idx) {
-                        cosmic_edit.editor.buffer_mut().lines.clear();
-                        for line in current_edit.lines.iter() {
-                            let mut line_text = String::new();
-                            let mut attrs_list = AttrsList::new(cosmic_edit.attrs.as_attrs());
-                            for (text, attrs) in line.iter() {
-                                let start = line_text.len();
-                                line_text.push_str(text);
-                                let end = line_text.len();
-                                attrs_list.add_span(start..end, attrs.as_attrs());
-                            }
-                            cosmic_edit.editor.buffer_mut().lines.push(BufferLine::new(
-                                line_text,
-                                attrs_list,
-                                Shaping::Advanced,
-                            ));
+                let idx = edit_history.current_edit - 1;
+                if let Some(current_edit) = edits.get(idx) {
+                    editor.buffer_mut().lines.clear();
+                    for line in current_edit.lines.iter() {
+                        let mut line_text = String::new();
+                        let mut attrs_list = AttrsList::new(attrs.as_attrs());
+                        for (text, attrs) in line.iter() {
+                            let start = line_text.len();
+                            line_text.push_str(text);
+                            let end = line_text.len();
+                            attrs_list.add_span(start..end, attrs.as_attrs());
                         }
-                        cosmic_edit.editor.set_cursor(current_edit.cursor);
-                        cosmic_edit.editor.buffer_mut().set_redraw(true);
-                        edit_history.current_edit += 1;
+                        editor.buffer_mut().lines.push(BufferLine::new(
+                            line_text,
+                            attrs_list,
+                            Shaping::Advanced,
+                        ));
                     }
-                    *undoredo_duration = Some(Duration::from_millis(now_ms as u64));
-                    // RETURN
-                    return;
+                    editor.set_cursor(current_edit.cursor);
+                    editor.buffer_mut().set_redraw(true);
+                    edit_history.current_edit -= 1;
                 }
-                // undo
-                let requested_undo = command && keys.just_pressed(KeyCode::Z);
-
-                if !cosmic_edit.readonly && requested_undo {
-                    let edits = &edit_history.edits;
-                    if edits.is_empty() {
-                        // RETURN
-                        return;
+                *undoredo_duration = Some(Duration::from_millis(now_ms as u64));
+                return;
+            }
+
+            let mut is_clipboard = false;
+            #[cfg(not(target_arch = "wasm32"))]
+            {
+                if let Ok(mut clipboard) = arboard::Clipboard::new() {
+                    if command && keys.just_pressed(KeyCode::C) {
+                        if let Some(text) = editor.copy_selection() {
+                            clipboard.set_text(text).unwrap();
+                            return;
+                        }
                     }
-                    if edit_history.current_edit <= 1 {
-                        // RETURN
-                        return;
+                    if !readonly && command && keys.just_pressed(KeyCode::X) {
+                        if let Some(text) = editor.copy_selection() {
+                            clipboard.set_text(text).unwrap();
+                            editor.delete_selection();
+                        }
+                        is_clipboard = true;
                     }
-                    let idx = edit_history.current_edit - 1;
-                    if let Some(current_edit) = edits.get(idx) {
-                        cosmic_edit.editor.buffer_mut().lines.clear();
-                        for line in current_edit.lines.iter() {
-                            let mut line_text = String::new();
-                            let mut attrs_list = AttrsList::new(cosmic_edit.attrs.as_attrs());
-                            for (text, attrs) in line.iter() {
-                                let start = line_text.len();
-                                line_text.push_str(text);
-                                let end = line_text.len();
-                                attrs_list.add_span(start..end, attrs.as_attrs());
+                    if !readonly && command && keys.just_pressed(KeyCode::V) {
+                        if let Ok(text) = clipboard.get_text() {
+                            for c in text.chars() {
+                                editor.action(&mut font_system.0, Action::Insert(c));
                             }
-                            cosmic_edit.editor.buffer_mut().lines.push(BufferLine::new(
-                                line_text,
-                                attrs_list,
-                                Shaping::Advanced,
-                            ));
                         }
-                        cosmic_edit.editor.set_cursor(current_edit.cursor);
-                        cosmic_edit.editor.buffer_mut().set_redraw(true);
-                        edit_history.current_edit -= 1;
+                        is_clipboard = true;
                     }
-                    *undoredo_duration = Some(Duration::from_millis(now_ms as u64));
-                    // RETURN
-                    return;
                 }
+            }
+            let (offset_x, offset_y) = match text_position {
+                CosmicTextPosition::Center => {
+                    (get_x_offset(editor.buffer()), get_y_offset(editor.buffer()))
+                }
+                CosmicTextPosition::TopLeft => (0, 0),
+            };
+            let point = |node_cursor_pos: (f32, f32)| {
+                (
+                    (node_cursor_pos.0 * scale_factor) as i32 - offset_x,
+                    (node_cursor_pos.1 * scale_factor) as i32 - offset_y,
+                )
+            };
 
-                let mut is_clipboard = false;
-                #[cfg(not(target_arch = "wasm32"))]
-                {
-                    if let Ok(mut clipboard) = arboard::Clipboard::new() {
-                        if command && keys.just_pressed(KeyCode::C) {
-                            if let Some(text) = cosmic_edit.editor.copy_selection() {
-                                clipboard.set_text(text).unwrap();
-                                // RETURN
-                                return;
-                            }
-                        }
-                        if !cosmic_edit.readonly && command && keys.just_pressed(KeyCode::X) {
-                            if let Some(text) = cosmic_edit.editor.copy_selection() {
-                                clipboard.set_text(text).unwrap();
-                                cosmic_edit.editor.delete_selection();
-                            }
-                            is_clipboard = true;
-                        }
-                        if !cosmic_edit.readonly && command && keys.just_pressed(KeyCode::V) {
-                            if let Ok(text) = clipboard.get_text() {
-                                for c in text.chars() {
-                                    cosmic_edit
-                                        .editor
-                                        .action(&mut font_system.0, Action::Insert(c));
-                                }
-                            }
-                            is_clipboard = true;
-                        }
+            if buttons.just_pressed(MouseButton::Left) {
+                if let Some(node_cursor_pos) = get_node_cursor_pos(
+                    primary_window,
+                    node_transform,
+                    (width, height),
+                    is_ui_node,
+                    camera,
+                    camera_transform,
+                ) {
+                    let (x, y) = point(node_cursor_pos);
+                    if shift {
+                        editor.action(&mut font_system.0, Action::Drag { x, y });
+                    } else {
+                        editor.action(&mut font_system.0, Action::Click { x, y });
                     }
                 }
-                let (offset_x, offset_y) = match cosmic_edit.text_pos {
-                    CosmicTextPos::Center => (
-                        get_x_offset(cosmic_edit.editor.buffer()),
-                        get_y_offset(cosmic_edit.editor.buffer()),
-                    ),
-                    CosmicTextPos::TopLeft => (0, 0),
-                };
-                let point = |node_cursor_pos: (f32, f32)| {
-                    (
-                        (node_cursor_pos.0 * scale_factor) as i32 - offset_x,
-                        (node_cursor_pos.1 * scale_factor) as i32 - offset_y,
-                    )
-                };
-                if buttons.just_pressed(MouseButton::Left) {
-                    if let Some(node_cursor_pos) = get_node_cursor_pos(
-                        primary_window,
-                        node_transform,
-                        (cosmic_edit.width, cosmic_edit.height),
-                        cosmic_edit.is_ui_node,
-                        camera,
-                        camera_transform,
-                    ) {
-                        let (x, y) = point(node_cursor_pos);
-                        if shift {
-                            cosmic_edit
-                                .editor
-                                .action(&mut font_system.0, Action::Drag { x, y });
-                        } else {
-                            cosmic_edit
-                                .editor
-                                .action(&mut font_system.0, Action::Click { x, y });
-                        }
-                    }
-                    // RETURN
-                    return;
+                return;
+            }
+            if buttons.pressed(MouseButton::Left) {
+                if let Some(node_cursor_pos) = get_node_cursor_pos(
+                    primary_window,
+                    node_transform,
+                    (width, height),
+                    is_ui_node,
+                    camera,
+                    camera_transform,
+                ) {
+                    let (x, y) = point(node_cursor_pos);
+                    editor.action(&mut font_system.0, Action::Drag { x, y });
                 }
-                if buttons.pressed(MouseButton::Left) {
-                    if let Some(node_cursor_pos) = get_node_cursor_pos(
-                        primary_window,
-                        node_transform,
-                        (cosmic_edit.width, cosmic_edit.height),
-                        cosmic_edit.is_ui_node,
-                        camera,
-                        camera_transform,
-                    ) {
-                        let (x, y) = point(node_cursor_pos);
-                        cosmic_edit
-                            .editor
-                            .action(&mut font_system.0, Action::Drag { x, y });
+                return;
+            }
+            for ev in scroll_evr.iter() {
+                match ev.unit {
+                    MouseScrollUnit::Line => {
+                        editor.action(
+                            &mut font_system.0,
+                            Action::Scroll {
+                                lines: -ev.y as i32,
+                            },
+                        );
                     }
-                    // RETURN
-                    return;
-                }
-                for ev in scroll_evr.iter() {
-                    match ev.unit {
-                        MouseScrollUnit::Line => {
-                            cosmic_edit.editor.action(
-                                &mut font_system.0,
-                                Action::Scroll {
-                                    lines: -ev.y as i32,
-                                },
-                            );
-                        }
-                        MouseScrollUnit::Pixel => {
-                            let line_height = cosmic_edit.editor.buffer().metrics().line_height;
-                            cosmic_edit.editor.action(
-                                &mut font_system.0,
-                                Action::Scroll {
-                                    lines: -(ev.y / line_height) as i32,
-                                },
-                            );
-                        }
+                    MouseScrollUnit::Pixel => {
+                        let line_height = editor.buffer().metrics().line_height;
+                        editor.action(
+                            &mut font_system.0,
+                            Action::Scroll {
+                                lines: -(ev.y / line_height) as i32,
+                            },
+                        );
                     }
                 }
+            }
 
-                if cosmic_edit.readonly {
-                    // RETURN
-                    return;
-                }
+            if readonly {
+                return;
+            }
 
-                let mut is_edit = is_clipboard;
-                let mut is_return = false;
-                if keys.just_pressed(KeyCode::Return) {
-                    is_return = true;
-                    is_edit = true;
-                    // to have new line on wasm rather than E
-                    cosmic_edit
-                        .editor
-                        .action(&mut font_system.0, Action::Insert('\n'));
-                }
+            let mut is_edit = is_clipboard;
+            let mut is_return = false;
+            if keys.just_pressed(KeyCode::Return) {
+                is_return = true;
+                is_edit = true;
+                // to have new line on wasm rather than E
+                editor.action(&mut font_system.0, Action::Insert('\n'));
+            }
 
-                if !(is_clipboard || is_return) {
-                    for char_ev in char_evr.iter() {
-                        is_edit = true;
-                        if *is_deleting {
-                            cosmic_edit
-                                .editor
-                                .action(&mut font_system.0, Action::Backspace);
-                        } else {
-                            cosmic_edit
-                                .editor
-                                .action(&mut font_system.0, Action::Insert(char_ev.char));
-                        }
+            if !(is_clipboard || is_return) {
+                for char_ev in char_evr.iter() {
+                    is_edit = true;
+                    if *is_deleting {
+                        editor.action(&mut font_system.0, Action::Backspace);
+                    } else {
+                        editor.action(&mut font_system.0, Action::Insert(char_ev.char));
                     }
                 }
+            }
 
-                if !is_edit {
-                    // RETURN
-                    return;
-                }
+            if !is_edit {
+                return;
+            }
 
-                if let Some(last_edit_duration) = *edits_duration {
-                    if Duration::from_millis(now_ms as u64) - last_edit_duration
-                        > Duration::from_millis(150)
-                    {
-                        save_edit_history(&mut cosmic_edit, &mut edit_history);
-                        *edits_duration = Some(Duration::from_millis(now_ms as u64));
-                    }
-                } else {
-                    save_edit_history(&mut cosmic_edit, &mut edit_history);
+            if let Some(last_edit_duration) = *edits_duration {
+                if Duration::from_millis(now_ms as u64) - last_edit_duration
+                    > Duration::from_millis(150)
+                {
+                    save_edit_history(editor, attrs, &mut edit_history);
                     *edits_duration = Some(Duration::from_millis(now_ms as u64));
                 }
+            } else {
+                save_edit_history(editor, attrs, &mut edit_history);
+                *edits_duration = Some(Duration::from_millis(now_ms as u64));
             }
         }
     }
 }
 
-fn cosmic_edit_set_redraw(mut cosmic_edit_query: Query<&mut CosmicEdit, Added<CosmicEdit>>) {
-    for mut cosmic_edit in cosmic_edit_query.iter_mut() {
-        cosmic_edit.editor.buffer_mut().set_redraw(true);
+fn cosmic_edit_set_redraw(mut cosmic_edit_query: Query<&mut CosmicEditor, Added<CosmicEditor>>) {
+    for mut editor in cosmic_edit_query.iter_mut() {
+        editor.0.buffer_mut().set_redraw(true);
     }
 }
 
+#[allow(clippy::too_many_arguments)]
 fn redraw_buffer_common(
     images: &mut ResMut<Assets<Image>>,
     swash_cache_state: &mut ResMut<SwashCacheState>,
-    cosmic_edit: &mut CosmicEdit,
-    img_handle: &mut Handle<Image>,
-    font_system_assets: &mut ResMut<Assets<CosmicFont>>,
+    editor: &mut Editor,
+    background_image: Option<Handle<Image>>,
+    background_color: Color,
+    cosmic_canvas_img_handle: &mut Handle<Image>,
+    text_position: &CosmicTextPosition,
+    font_system: &mut ResMut<CosmicFontSystem>,
     scale_factor: f32,
     original_width: f32,
     original_height: f32,
@@ -791,96 +1021,90 @@ fn redraw_buffer_common(
     let width = original_width * scale_factor;
     let height = original_height * scale_factor;
     let swash_cache = &mut swash_cache_state.swash_cache;
-    if let Some(font_system) = font_system_assets.get_mut(&cosmic_edit.font_system) {
-        cosmic_edit.editor.shape_as_needed(&mut font_system.0);
-        if cosmic_edit.editor.buffer().redraw() {
-            cosmic_edit
-                .editor
-                .buffer_mut()
-                .set_size(&mut font_system.0, width, height);
-            let font_color = cosmic_text::Color::rgb(0, 0, 0);
-
-            let mut pixels = vec![0; width as usize * height as usize * 4];
-            if let Some(bg_image) = cosmic_edit.bg_image.clone() {
-                let image = images.get(&bg_image).unwrap();
-
-                let mut dynamic_image = image.clone().try_into_dynamic().unwrap();
-                if image.size().x != width || image.size().y != height {
-                    dynamic_image = dynamic_image.resize_to_fill(
-                        width as u32,
-                        height as u32,
-                        FilterType::Triangle,
-                    );
-                }
-                for (i, (_, _, rgba)) in dynamic_image.pixels().enumerate() {
-                    if let Some(p) = pixels.get_mut(i * 4..(i + 1) * 4) {
-                        p[0] = rgba[0];
-                        p[1] = rgba[1];
-                        p[2] = rgba[2];
-                        p[3] = rgba[3];
-                    }
-                }
-            } else {
-                let bg = cosmic_edit.bg;
-                for pixel in pixels.chunks_exact_mut(4) {
-                    pixel[0] = (bg.r() * 255.) as u8; // Red component
-                    pixel[1] = (bg.g() * 255.) as u8; // Green component
-                    pixel[2] = (bg.b() * 255.) as u8; // Blue component
-                    pixel[3] = (bg.a() * 255.) as u8; // Alpha component
+    editor.shape_as_needed(&mut font_system.0);
+    if editor.buffer().redraw() {
+        editor
+            .buffer_mut()
+            .set_size(&mut font_system.0, width, height);
+        let font_color = cosmic_text::Color::rgb(0, 0, 0);
+
+        let mut pixels = vec![0; width as usize * height as usize * 4];
+        if let Some(bg_image) = background_image {
+            let image = images.get(&bg_image).unwrap();
+
+            let mut dynamic_image = image.clone().try_into_dynamic().unwrap();
+            if image.size().x != width || image.size().y != height {
+                dynamic_image =
+                    dynamic_image.resize_to_fill(width as u32, height as u32, FilterType::Triangle);
+            }
+            for (i, (_, _, rgba)) in dynamic_image.pixels().enumerate() {
+                if let Some(p) = pixels.get_mut(i * 4..(i + 1) * 4) {
+                    p[0] = rgba[0];
+                    p[1] = rgba[1];
+                    p[2] = rgba[2];
+                    p[3] = rgba[3];
                 }
             }
+        } else {
+            let bg = background_color;
+            for pixel in pixels.chunks_exact_mut(4) {
+                pixel[0] = (bg.r() * 255.) as u8; // Red component
+                pixel[1] = (bg.g() * 255.) as u8; // Green component
+                pixel[2] = (bg.b() * 255.) as u8; // Blue component
+                pixel[3] = (bg.a() * 255.) as u8; // Alpha component
+            }
+        }
 
-            let (offset_y, offset_x) = match cosmic_edit.text_pos {
-                CosmicTextPos::Center => (
-                    get_y_offset(cosmic_edit.editor.buffer()),
-                    get_x_offset(cosmic_edit.editor.buffer()),
-                ),
-                CosmicTextPos::TopLeft => (0, 0),
-            };
-            cosmic_edit.editor.draw(
-                &mut font_system.0,
-                swash_cache,
-                font_color,
-                |x, y, w, h, color| {
-                    for row in 0..h as i32 {
-                        for col in 0..w as i32 {
-                            draw_pixel(
-                                &mut pixels,
-                                width as i32,
-                                height as i32,
-                                x + col + offset_x,
-                                y + row + offset_y,
-                                color,
-                            );
-                        }
+        let (offset_y, offset_x) = match text_position {
+            CosmicTextPosition::Center => {
+                (get_y_offset(editor.buffer()), get_x_offset(editor.buffer()))
+            }
+            CosmicTextPosition::TopLeft => (0, 0),
+        };
+
+        editor.draw(
+            &mut font_system.0,
+            swash_cache,
+            font_color,
+            |x, y, w, h, color| {
+                for row in 0..h as i32 {
+                    for col in 0..w as i32 {
+                        draw_pixel(
+                            &mut pixels,
+                            width as i32,
+                            height as i32,
+                            x + col + offset_x,
+                            y + row + offset_y,
+                            color,
+                        );
                     }
-                },
-            );
-            cosmic_edit.editor.buffer_mut().set_redraw(false);
-
-            if let Some(prev_image) = images.get_mut(img_handle) {
-                if *img_handle == bevy::render::texture::DEFAULT_IMAGE_HANDLE.typed() {
-                    let mut prev_image = prev_image.clone();
-                    prev_image.data.clear();
-                    prev_image.data.extend_from_slice(pixels.as_slice());
-                    prev_image.resize(Extent3d {
-                        width: width as u32,
-                        height: height as u32,
-                        depth_or_array_layers: 1,
-                    });
-                    let handle_id: HandleId = HandleId::random::<Image>();
-                    let new_handle: Handle<Image> = Handle::weak(handle_id);
-                    let new_handle = images.set(new_handle, prev_image);
-                    *img_handle = new_handle;
-                } else {
-                    prev_image.data.clear();
-                    prev_image.data.extend_from_slice(pixels.as_slice());
-                    prev_image.resize(Extent3d {
-                        width: width as u32,
-                        height: height as u32,
-                        depth_or_array_layers: 1,
-                    });
                 }
+            },
+        );
+        editor.buffer_mut().set_redraw(false);
+
+        if let Some(prev_image) = images.get_mut(cosmic_canvas_img_handle) {
+            if *cosmic_canvas_img_handle == bevy::render::texture::DEFAULT_IMAGE_HANDLE.typed() {
+                let mut prev_image = prev_image.clone();
+                prev_image.data.clear();
+                prev_image.data.extend_from_slice(pixels.as_slice());
+                prev_image.resize(Extent3d {
+                    width: width as u32,
+                    height: height as u32,
+                    depth_or_array_layers: 1,
+                });
+                let handle_id: HandleId = HandleId::random::<Image>();
+                let new_handle: Handle<Image> = Handle::weak(handle_id);
+                let new_handle = images.set(new_handle, prev_image);
+                *cosmic_canvas_img_handle = new_handle;
+            } else {
+                prev_image.data.clear();
+                prev_image.data.extend_from_slice(pixels.as_slice());
+                prev_image.resize(Extent3d {
+                    width: width as u32,
+                    height: height as u32,
+                    depth_or_array_layers: 1,
+                });
             }
         }
     }
@@ -890,27 +1114,41 @@ fn cosmic_edit_redraw_buffer_ui(
     windows: Query<&Window, With<PrimaryWindow>>,
     mut images: ResMut<Assets<Image>>,
     mut swash_cache_state: ResMut<SwashCacheState>,
-    mut cosmic_edit_query: Query<
-        (&mut CosmicEdit, &mut UiImage, &Node, &mut Visibility),
-        With<CosmicEdit>,
-    >,
-    mut font_system_assets: ResMut<Assets<CosmicFont>>,
+    mut cosmic_edit_query: Query<(
+        &mut CosmicEditor,
+        &CosmicBackground,
+        &BackgroundColor,
+        &CosmicTextPosition,
+        &mut UiImage,
+        &Node,
+        &mut Visibility,
+    )>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     let primary_window = windows.single();
-    for (mut cosmic_edit, mut img, node, mut visibility) in &mut cosmic_edit_query.iter_mut() {
-        if node.size().x != 0. && node.size().y != 0. {
-            cosmic_edit.width = node.size().x;
-            cosmic_edit.height = node.size().y;
-        }
-        let width = cosmic_edit.width;
-        let height = cosmic_edit.height;
+    for (
+        mut editor,
+        background_image,
+        background_color,
+        text_position,
+        mut img,
+        node,
+        mut visibility,
+    ) in &mut cosmic_edit_query.iter_mut()
+    {
+        // provide min sizes to prevent render panic
+        let width = node.size().x.max(1.);
+        let height = node.size().y.max(1.);
 
         redraw_buffer_common(
             &mut images,
             &mut swash_cache_state,
-            &mut cosmic_edit,
+            &mut editor.0,
+            background_image.0.clone(),
+            background_color.0,
             &mut img.texture,
-            &mut font_system_assets,
+            text_position,
+            &mut font_system,
             primary_window.scale_factor() as f32,
             width,
             height,
@@ -928,22 +1166,41 @@ fn cosmic_edit_redraw_buffer(
     windows: Query<&Window, With<PrimaryWindow>>,
     mut images: ResMut<Assets<Image>>,
     mut swash_cache_state: ResMut<SwashCacheState>,
-    mut cosmic_edit_query: Query<
-        (&mut CosmicEdit, &mut Handle<Image>, &mut Visibility),
-        With<CosmicEdit>,
-    >,
-    mut font_system_assets: ResMut<Assets<CosmicFont>>,
+    mut cosmic_edit_query: Query<(
+        &mut CosmicEditor,
+        &Sprite,
+        &CosmicBackground,
+        &BackgroundColor,
+        &CosmicTextPosition,
+        &mut Handle<Image>,
+        &mut Visibility,
+    )>,
+    mut font_system: ResMut<CosmicFontSystem>,
 ) {
     let primary_window = windows.single();
-    for (mut cosmic_edit, mut handle, mut visibility) in &mut cosmic_edit_query.iter_mut() {
-        let width = cosmic_edit.width;
-        let height = cosmic_edit.height;
+    for (
+        mut editor,
+        sprite,
+        background_image,
+        background_color,
+        text_position,
+        mut handle,
+        mut visibility,
+    ) in &mut cosmic_edit_query.iter_mut()
+    {
+        // provide min sizes to prevent render panic
+        let width = sprite.custom_size.unwrap().x.max(1.);
+        let height = sprite.custom_size.unwrap().y.max(1.);
+
         redraw_buffer_common(
             &mut images,
             &mut swash_cache_state,
-            &mut cosmic_edit,
+            &mut editor.0,
+            background_image.0.clone(),
+            background_color.0,
             &mut handle,
-            &mut font_system_assets,
+            text_position,
+            &mut font_system,
             primary_window.scale_factor() as f32,
             width,
             height,
@@ -957,143 +1214,6 @@ fn cosmic_edit_redraw_buffer(
     }
 }
 
-pub fn cosmic_edit_set_text(
-    text: CosmicText,
-    attrs: AttrsOwned,
-    editor: &mut Editor,
-    font_system: &mut FontSystem,
-) {
-    editor.buffer_mut().lines.clear();
-    match text {
-        CosmicText::OneStyle(text) => {
-            editor.buffer_mut().set_text(
-                font_system,
-                text.as_str(),
-                attrs.as_attrs(),
-                Shaping::Advanced,
-            );
-        }
-        CosmicText::MultiStyle(lines) => {
-            for line in lines {
-                let mut line_text = String::new();
-                let mut attrs_list = AttrsList::new(attrs.as_attrs());
-                for (text, attrs) in line.iter() {
-                    let start = line_text.len();
-                    line_text.push_str(text);
-                    let end = line_text.len();
-                    attrs_list.add_span(start..end, attrs.as_attrs());
-                }
-                editor.buffer_mut().lines.push(BufferLine::new(
-                    line_text,
-                    attrs_list,
-                    Shaping::Advanced,
-                ));
-            }
-        }
-    }
-}
-
-/// Spawns a cosmic edit entity with the provided configuration.
-///
-/// # Returns
-///
-/// The `Entity` identifier of the spawned cosmic edit entity.
-pub fn spawn_cosmic_edit(
-    commands: &mut Commands,
-    cosmic_fonts: &mut ResMut<Assets<CosmicFont>>,
-    cosmic_edit_meta: CosmicEditMeta,
-) -> Entity {
-    let font_system = cosmic_fonts
-        .get_mut(&cosmic_edit_meta.font_system_handle)
-        .unwrap();
-    let scale_factor = cosmic_edit_meta.metrics.scale_factor;
-    let font_size = cosmic_edit_meta.metrics.font_size;
-    let line_height = cosmic_edit_meta.metrics.line_height;
-    let metrics = Metrics::new(font_size, line_height).scale(scale_factor);
-    let buffer = Buffer::new(&mut font_system.0, metrics);
-    let mut editor = Editor::new(buffer);
-    cosmic_edit_set_text(
-        cosmic_edit_meta.text,
-        cosmic_edit_meta.attrs.clone(),
-        &mut editor,
-        &mut font_system.0,
-    );
-    if let Some((width, height)) = cosmic_edit_meta.size {
-        editor.buffer_mut().set_size(
-            &mut font_system.0,
-            width * scale_factor,
-            height * scale_factor,
-        );
-    }
-    let mut cursor = editor.cursor();
-    if cosmic_edit_meta.readonly {
-        cursor.color = Some(bevy_color_to_cosmic(cosmic_edit_meta.bg));
-    }
-    editor.set_cursor(cursor);
-
-    let mut edits = VecDeque::new();
-    if !cosmic_edit_meta.readonly {
-        edits.push_back(EditHistoryItem {
-            cursor,
-            lines: get_text_spans(editor.buffer(), cosmic_edit_meta.attrs.clone()),
-        });
-    }
-    let edit_history = CosmicEditHistory {
-        edits,
-        current_edit: 0,
-    };
-    let mut cosmic_edit_component = CosmicEdit {
-        editor,
-        font_system: cosmic_edit_meta.font_system_handle,
-        text_pos: cosmic_edit_meta.text_pos,
-        bg: cosmic_edit_meta.bg,
-        is_ui_node: false,
-        font_size,
-        line_height,
-        width: cosmic_edit_meta.size.unwrap_or((1., 1.)).0,
-        height: cosmic_edit_meta.size.unwrap_or((1., 1.)).1,
-        readonly: cosmic_edit_meta.readonly,
-        attrs: cosmic_edit_meta.attrs.clone(),
-        bg_image: cosmic_edit_meta.bg_image,
-    };
-    match cosmic_edit_meta.node {
-        CosmicNode::Ui => {
-            cosmic_edit_component.is_ui_node = true;
-            let style = Style {
-                width: Val::Percent(100.),
-                height: Val::Percent(100.),
-                ..default()
-            };
-            let button_bundle = ButtonBundle {
-                visibility: Visibility::Hidden,
-                focus_policy: bevy::ui::FocusPolicy::Pass,
-                style,
-                ..default()
-            };
-            commands
-                .spawn((button_bundle, cosmic_edit_component, edit_history))
-                .id()
-        }
-        CosmicNode::Sprite(sprite_node) => {
-            let sprite = SpriteBundle {
-                visibility: Visibility::Hidden,
-                sprite: Sprite {
-                    custom_size: Some(Vec2::new(
-                        cosmic_edit_component.width,
-                        cosmic_edit_component.height,
-                    )),
-                    ..default()
-                },
-                transform: sprite_node.transform,
-                ..default()
-            };
-            commands
-                .spawn((sprite, cosmic_edit_component, edit_history))
-                .id()
-        }
-    }
-}
-
 fn draw_pixel(
     buffer: &mut [u8],
     width: i32,
@@ -1145,39 +1265,17 @@ fn draw_pixel(
 
 #[cfg(test)]
 mod tests {
-    use bevy::prelude::*;
-    use cosmic_text::{Attrs, AttrsOwned};
-
     use crate::*;
 
     fn test_spawn_cosmic_edit_system(
         mut commands: Commands,
-        mut cosmic_fonts: ResMut<Assets<CosmicFont>>,
+        mut font_system: ResMut<CosmicFontSystem>,
     ) {
-        let cosmic_font_config = CosmicFontConfig {
-            fonts_dir_path: None,
-            font_bytes: None,
-            load_system_fonts: true,
-        };
-        let font_system = create_cosmic_font_system(cosmic_font_config);
-        let font_system_handle = cosmic_fonts.add(CosmicFont(font_system));
-        let cosmic_edit_meta = CosmicEditMeta {
-            text: CosmicText::OneStyle("Blah".to_string()),
-            attrs: AttrsOwned::new(Attrs::new()),
-            metrics: CosmicMetrics {
-                font_size: 14.,
-                line_height: 18.,
-                scale_factor: 1.,
-            },
-            text_pos: CosmicTextPos::Center,
-            font_system_handle,
-            node: CosmicNode::Ui,
-            size: None,
-            bg: bevy::prelude::Color::NONE,
-            readonly: false,
-            bg_image: None,
-        };
-        spawn_cosmic_edit(&mut commands, &mut cosmic_fonts, cosmic_edit_meta);
+        commands.spawn(CosmicEditUiBundle::default().set_text(
+            CosmicText::OneStyle("Blah".into()),
+            AttrsOwned::new(Attrs::new()),
+            &mut font_system.0,
+        ));
     }
 
     #[test]
@@ -1185,6 +1283,9 @@ mod tests {
         let mut app = App::new();
         app.add_plugins(TaskPoolPlugin::default());
         app.add_plugins(AssetPlugin::default());
+        app.insert_resource(CosmicFontSystem(create_cosmic_font_system(
+            CosmicFontConfig::default(),
+        )));
         app.add_systems(Update, test_spawn_cosmic_edit_system);
 
         let input = Input::<KeyCode>::default();
@@ -1192,16 +1293,15 @@ mod tests {
         let mouse_input: Input<MouseButton> = Input::<MouseButton>::default();
         app.insert_resource(mouse_input);
         app.add_asset::<Image>();
-        app.add_asset::<CosmicFont>();
 
         app.add_event::<ReceivedCharacter>();
 
         app.update();
 
-        let mut text_nodes_query = app.world.query::<&CosmicEdit>();
-        for node in text_nodes_query.iter(&app.world) {
-            insta::assert_debug_snapshot!(node
-                .editor
+        let mut text_nodes_query = app.world.query::<&CosmicEditor>();
+        for cosmic_editor in text_nodes_query.iter(&app.world) {
+            insta::assert_debug_snapshot!(cosmic_editor
+                .0
                 .buffer()
                 .lines
                 .iter()
diff --git a/src/utils.rs b/src/utils.rs
index 8728dda5ac6469cbbf08a5ab5a6496b20edabfeb..b3d72d9f081f61ad21e7b53265798d03cc2381b4 100644
--- a/src/utils.rs
+++ b/src/utils.rs
@@ -10,3 +10,59 @@ pub fn get_timestamp() -> f64 {
     let duration = SystemTime::now().duration_since(UNIX_EPOCH).unwrap();
     duration.as_millis() as f64
 }
+
+use crate::{ActiveEditor, CosmicEditor, ReadOnly};
+use bevy::{prelude::*, ui::Interaction, window::PrimaryWindow};
+
+// util fns for examples
+//
+pub fn change_active_editor_ui(
+    mut commands: Commands,
+    mut interaction_query: Query<
+        (&Interaction, Entity),
+        (
+            Changed<Interaction>,
+            (With<CosmicEditor>, Without<ReadOnly>),
+        ),
+    >,
+) {
+    for (interaction, entity) in interaction_query.iter_mut() {
+        if let Interaction::Pressed = interaction {
+            commands.insert_resource(ActiveEditor {
+                entity: Some(entity),
+            });
+        }
+    }
+}
+
+pub fn change_active_editor_sprite(
+    mut commands: Commands,
+    windows: Query<&Window, With<PrimaryWindow>>,
+    buttons: Res<Input<MouseButton>>,
+    mut cosmic_edit_query: Query<
+        (&mut Sprite, &GlobalTransform, Entity),
+        (With<CosmicEditor>, Without<ReadOnly>),
+    >,
+    camera_q: Query<(&Camera, &GlobalTransform)>,
+) {
+    let window = windows.single();
+    let (camera, camera_transform) = camera_q.single();
+    if buttons.just_pressed(MouseButton::Left) {
+        for (sprite, node_transform, entity) in &mut cosmic_edit_query.iter_mut() {
+            let size = sprite.custom_size.unwrap_or(Vec2::new(1., 1.));
+            let x_min = node_transform.affine().translation.x - size.x / 2.;
+            let y_min = node_transform.affine().translation.y - size.y / 2.;
+            let x_max = node_transform.affine().translation.x + size.x / 2.;
+            let y_max = node_transform.affine().translation.y + size.y / 2.;
+            if let Some(pos) = window.cursor_position() {
+                if let Some(pos) = camera.viewport_to_world_2d(camera_transform, pos) {
+                    if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max {
+                        commands.insert_resource(ActiveEditor {
+                            entity: Some(entity),
+                        });
+                    };
+                }
+            };
+        }
+    }
+}