diff --git a/engine/src/core/render/ctx.rs b/engine/src/core/render/ctx.rs
index addd7dc..cc65270 100644
--- a/engine/src/core/render/ctx.rs
+++ b/engine/src/core/render/ctx.rs
@@ -1,20 +1,133 @@
-use std::borrow::Cow;
 use std::sync::Arc;
 use std::time::Instant;
+use std::{backtrace::Backtrace, borrow::Cow};
 
 use cgmath::{Matrix4, Point3, Rad, Vector3, perspective};
 use futures::executor::block_on;
 use thiserror::Error;
+use tracing::{error, trace};
+use wgpu::TextureUsages;
 use wgpu::{Backends, InstanceDescriptor, util::DeviceExt};
 use winit::window::Window;
-
 #[derive(Debug, Error)]
-pub enum ContextError {
-    #[error("Failed to create WGPU surface: {0}")]
-    SurfaceCreationFailure(#[from] wgpu::CreateSurfaceError),
+#[error(transparent)]
+pub enum ContextErrorKind {
+    #[error("Surface creation failed")]
+    SurfaceCreation,
+    #[error("Surface configuration failed")]
+    SurfaceConfiguration,
+    #[error("Adapter request failed")]
+    AdapterRequest,
+    #[error("Device request failed")]
+    DeviceRequest,
+    #[error("Surface texture acquisition failed")]
+    SurfaceTexture,
 }
 
-const CUBE_SHADER: &str = r#"
+#[derive(Debug, Error)]
+pub struct RenderContextError {
+    kind: ContextErrorKind,
+    label: Option<Cow<'static, str>>,
+    #[source]
+    source: Option<Box<dyn std::error::Error + Send + Sync>>,
+}
+
+impl RenderContextError {
+    pub fn new(
+        kind: ContextErrorKind,
+        label: impl Into<Option<Cow<'static, str>>>,
+        source: impl Into<Option<Box<dyn std::error::Error + Send + Sync>>>,
+    ) -> Self {
+        Self {
+            kind,
+            label: label.into(),
+            source: source.into(),
+        }
+    }
+
+    pub fn with_label(mut self, label: impl Into<Cow<'static, str>>) -> Self {
+        self.label = Some(label.into());
+        self
+    }
+}
+
+impl std::fmt::Display for RenderContextError {
+    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+        if let Some(label) = &self.label {
+            writeln!(f, "[{}] {}", label, self.kind)?;
+        } else {
+            writeln!(f, "{}", self.kind)?;
+        }
+
+        if let Some(source) = &self.source {
+            fn fmt_chain(
+                err: &(dyn std::error::Error + 'static),
+                indent: usize,
+                f: &mut std::fmt::Formatter<'_>,
+            ) -> std::fmt::Result {
+                let indent_str = "  ".repeat(indent);
+                writeln!(f, "{}{}", indent_str, err)?;
+                if let Some(next) = err.source() {
+                    writeln!(f, "{}Caused by:", indent_str)?;
+                    fmt_chain(next, indent + 1, f)?;
+                }
+                Ok(())
+            }
+            writeln!(f, "Caused by:")?;
+            fmt_chain(source.as_ref(), 1, f)?;
+        }
+        Ok(())
+    }
+}
+
+trait IntoRenderContextError<T> {
+    fn ctx_err(
+        self,
+        kind: ContextErrorKind,
+        label: impl Into<Cow<'static, str>>,
+    ) -> Result<T, RenderContextError>;
+}
+
+impl<T, E> IntoRenderContextError<T> for Result<T, E>
+where
+    E: std::error::Error + Send + Sync + 'static,
+{
+    fn ctx_err(
+        self,
+        kind: ContextErrorKind,
+        label: impl Into<Cow<'static, str>>,
+    ) -> Result<T, RenderContextError> {
+        self.map_err(|e| {
+            RenderContextError::new(
+                kind,
+                Some(label.into()),
+                Some(Box::new(e) as Box<dyn std::error::Error + Send + Sync>),
+            )
+        })
+    }
+}
+
+impl From<wgpu::CreateSurfaceError> for RenderContextError {
+    fn from(err: wgpu::CreateSurfaceError) -> Self {
+        RenderContextError::new(
+            ContextErrorKind::SurfaceCreation,
+            Some("Surface creation".into()),
+            Some(Box::new(err) as Box<dyn std::error::Error + Send + Sync>),
+        )
+    }
+}
+
+impl From<wgpu::RequestDeviceError> for RenderContextError {
+    fn from(err: wgpu::RequestDeviceError) -> Self {
+        RenderContextError::new(
+            ContextErrorKind::DeviceRequest,
+            Some("Device setup".into()),
+            Some(Box::new(err) as Box<dyn std::error::Error + Send + Sync>),
+        )
+    }
+}
+
+const CUBE_SHADER: &str = r"
 struct Uniforms {
     mvp: mat4x4<f32>,
 };
@@ -40,14 +153,17 @@ fn vs_main(input: VertexInput) -> VertexOutput {
     return output;
 }
 
+
 @fragment
 fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
+    let ambient: f32 = 0.2;
     let light_dir = normalize(vec3<f32>(0.5, 1.0, 0.5));
-    let brightness = clamp(dot(normalize(input.normal), light_dir), 0.0, 1.0);
+    let diffuse = clamp(dot(normalize(input.normal), light_dir), 0.0, 1.0);
+    // Mix ambient light to ensure no face is completely dark.
+    let brightness = ambient + (1.0 - ambient) * diffuse;
     return vec4<f32>(0.7 * brightness, 0.7 * brightness, 0.9 * brightness, 1.0);
 }
-"#;
-
+";
 #[repr(C)]
 #[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
 struct Vertex {
@@ -236,39 +352,52 @@ pub struct WgpuCtx<'window> {
     vertex_buffer: wgpu::Buffer,
     start_time: Instant,
     bg_color: wgpu::Color,
+    last_frame_instant: Instant,
+    frame_count: u32,
 }
 
 impl<'window> WgpuCtx<'window> {
-    pub async fn new(window: Arc<Window>) -> Result<WgpuCtx<'window>, ContextError> {
+    pub async fn new(window: Arc<Window>) -> Result<WgpuCtx<'window>, RenderContextError> {
         let instance = wgpu::Instance::new(&InstanceDescriptor {
             backends: Backends::from_comma_list("dx12,metal,opengl,webgpu"),
             ..Default::default()
         });
-        let surface = instance.create_surface(Arc::clone(&window))?;
+
+        let surface = instance
+            .create_surface(Arc::clone(&window))
+            .ctx_err(ContextErrorKind::SurfaceCreation, "Surface initialization")?;
+
         let adapter = instance
             .request_adapter(&wgpu::RequestAdapterOptions {
                 power_preference: wgpu::PowerPreference::default(),
-                force_fallback_adapter: false,
                 compatible_surface: Some(&surface),
+                ..Default::default()
             })
             .await
-            .expect("Failed to obtain render adapter");
+            .ok_or_else(|| {
+                RenderContextError::new(
+                    ContextErrorKind::AdapterRequest,
+                    Some("Adapter selection".into()),
+                    None,
+                )
+            })?;
         let (device, queue) = adapter
-            .request_device(
-                &wgpu::DeviceDescriptor {
-                    label: None,
-                    required_features: wgpu::Features::empty(),
-                    required_limits: wgpu::Limits::default().using_resolution(adapter.limits()),
-                    memory_hints: wgpu::MemoryHints::Performance,
-                },
-                None,
-            )
+            .request_device(&wgpu::DeviceDescriptor::default(), None)
             .await
-            .expect("Failed to create rendering device");
+            .ctx_err(ContextErrorKind::DeviceRequest, "Device configuration")?;
         let size = window.inner_size();
         let width = size.width.max(1);
         let height = size.height.max(1);
-        let surface_config = surface.get_default_config(&adapter, width, height).unwrap();
+        let surface_config = wgpu::SurfaceConfiguration {
+            width: width.max(1),
+            height: height.max(1),
+            format: wgpu::TextureFormat::Rgba8UnormSrgb,
+            present_mode: wgpu::PresentMode::AutoNoVsync,
+            alpha_mode: wgpu::CompositeAlphaMode::Auto,
+            view_formats: Vec::new(),
+            usage: TextureUsages::RENDER_ATTACHMENT,
+            desired_maximum_frame_latency: 3,
+        };
         surface.configure(&device, &surface_config);
         let uniform_buffer = device.create_buffer(&wgpu::BufferDescriptor {
             label: Some("Uniform Buffer"),
@@ -356,10 +485,12 @@ impl<'window> WgpuCtx<'window> {
                 a: 1.0,
             },
             start_time: Instant::now(),
+            last_frame_instant: Instant::now(),
+            frame_count: 0,
         })
     }
 
-    pub fn new_blocking(window: Arc<Window>) -> Result<WgpuCtx<'window>, ContextError> {
+    pub fn new_blocking(window: Arc<Window>) -> Result<WgpuCtx<'window>, RenderContextError> {
         block_on(Self::new(window))
     }
 
@@ -431,6 +562,15 @@ impl<'window> WgpuCtx<'window> {
         }
         self.queue.submit(Some(encoder.finish()));
         surface_texture.present();
+
+        self.frame_count += 1;
+        let elapsed_secs = self.last_frame_instant.elapsed().as_secs_f32();
+        if elapsed_secs >= 1.0 {
+            let fps = self.frame_count as f32 / elapsed_secs;
+            trace!("FPS: {:.2}", fps);
+            self.frame_count = 0;
+            self.last_frame_instant = Instant::now();
+        }
     }
 
     pub fn change_bg_color(&mut self, color: wgpu::Color) {
diff --git a/engine/src/core/render/mod.rs b/engine/src/core/render/mod.rs
index b8cf30c..079c2cf 100644
--- a/engine/src/core/render/mod.rs
+++ b/engine/src/core/render/mod.rs
@@ -1,19 +1,29 @@
 use std::collections::HashMap;
+use std::ops::Deref;
 use std::sync::Arc;
 
 use ctx::WgpuCtx;
 use tracing::{debug, error, info, trace, warn};
+use wgpu::rwh::HasWindowHandle;
 use winit::application::ApplicationHandler;
-use winit::event::WindowEvent;
-use winit::event_loop::ControlFlow;
-use winit::event_loop::{ActiveEventLoop, EventLoop};
-use winit::window::{Window, WindowId};
+use winit::event::{KeyEvent, WindowEvent};
+use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
+use winit::window::Window;
+use winit::window::WindowId;
+
 pub mod ctx;
 
 struct WindowContext<'window> {
     window: Arc<Window>,
     ctx: WgpuCtx<'window>,
-    main_window: bool
+    main_window: bool,
+}
+impl Deref for WindowContext<'_> {
+    type Target = winit::window::Window;
+
+    fn deref(&self) -> &Self::Target {
+        self.window.as_ref()
+    }
 }
 impl WindowContext<'_> {
     pub fn is_main_window(&self) -> bool {
@@ -26,25 +36,155 @@ pub struct App<'window> {
     windows: HashMap<WindowId, WindowContext<'window>>,
 }
 
+impl App<'_> {
+    fn create_main_window(&mut self, event_loop: &ActiveEventLoop) {
+        let win_attr = Window::default_attributes().with_title("Zenyx");
+        match event_loop.create_window(win_attr) {
+            Ok(window) => {
+                let window = Arc::new(window);
+                let window_id = window.id();
+                match WgpuCtx::new_blocking(window.clone()) {
+                    Ok(wgpu_ctx) => {
+                        self.windows.insert(
+                            window_id,
+                            WindowContext {
+                                window,
+                                ctx: wgpu_ctx,
+                                main_window: true,
+                            },
+                        );
+                        info!("Main window created: {:?}", window_id);
+                    }
+                    Err(e) => error!("Failed to create WGPU context: {:?}", e),
+                }
+            }
+            Err(e) => error!("Failed to create main window: {:?}", e),
+        }
+    }
+
+    fn handle_close_requested(&mut self, window_id: WindowId) {
+        if self.windows.remove(&window_id).is_some() {
+            debug!("Window {:?} closed", window_id);
+        } else {
+            warn!("Tried to close non-existent window {:?}", window_id);
+        }
+    }
+
+    fn handle_keyboard_input(
+        &mut self,
+        event_loop: &ActiveEventLoop,
+        window_id: WindowId,
+        key_event: KeyEvent,
+    ) {
+        if !key_event.state.is_pressed() {
+            return;
+        }
+        match key_event.physical_key {
+            winit::keyboard::PhysicalKey::Code(code) => match code {
+                winit::keyboard::KeyCode::Space => {
+                    self.toggle_background(window_id);
+                }
+                winit::keyboard::KeyCode::Escape => {
+                    self.spawn_child_window(event_loop);
+                }
+                other => error!("Unimplemented keycode: {:?}", other),
+            },
+            _ => debug!("Received a keyboard event with no physical key"),
+        }
+    }
+
+    fn toggle_background(&mut self, window_id: WindowId) {
+        if let Some(window_context) = self.windows.get_mut(&window_id) {
+            let current_color = window_context.ctx.bg_color();
+            let new_color = match current_color {
+                wgpu::Color::WHITE => wgpu::Color::BLACK,
+                wgpu::Color::BLACK => wgpu::Color::WHITE,
+                _ => wgpu::Color::WHITE,
+            };
+            window_context.ctx.change_bg_color(new_color);
+            debug!("Toggled background color for window {:?}", window_id);
+        } else {
+            warn!("No window context for toggling background: {:?}", window_id);
+        }
+    }
+
+    fn spawn_child_window(&mut self, event_loop: &ActiveEventLoop) {
+        if let Some(main_ctx) = self.windows.values().find(|ctx| ctx.is_main_window()) {
+            let title = format!("Zenyx - New Window {}", self.windows.len());
+            //TODO: Verify that this is safe instead of matching on it
+            let win_attr = unsafe {
+                let base = Window::default_attributes().with_title(title);
+                match main_ctx.window_handle() {
+                    Ok(handle) => base.with_parent_window(Some(handle.as_raw())),
+                    Err(_) => base,
+                }
+            };
+            match event_loop.create_window(win_attr) {
+                Ok(window) => {
+                    let window = Arc::new(window);
+                    let window_id = window.id();
+                    match WgpuCtx::new_blocking(window.clone()) {
+                        Ok(wgpu_ctx) => {
+                            self.windows.insert(
+                                window_id,
+                                WindowContext {
+                                    window,
+                                    ctx: wgpu_ctx,
+                                    main_window: false,
+                                },
+                            );
+                            debug!("Spawned new child window: {:?}", window_id);
+                        }
+                        Err(e) => error!("Failed to create WGPU context for child window: {:?}", e),
+                    }
+                }
+                Err(e) => error!("Failed to create child window: {:?}", e),
+            }
+        } else {
+            error!("No main window found. Cannot spawn a child window.");
+        }
+    }
+
+    fn handle_redraw_requested(&mut self, window_id: WindowId) {
+        if let Some(window_context) = self.windows.get_mut(&window_id) {
+            window_context.ctx.draw();
+            window_context.request_redraw();
+            trace!(
+                "Redrew window {:?} with title: {}",
+                window_id,
+                window_context.window.title()
+            );
+        } else {
+            warn!("Received redraw for unknown window {:?}", window_id);
+        }
+    }
+
+    fn handle_resize(&mut self, window_id: WindowId, new_size: winit::dpi::PhysicalSize<u32>) {
+        if let Some(window_context) = self.windows.get_mut(&window_id) {
+            window_context.ctx.resize(new_size.into());
+            window_context.window.request_redraw();
+            debug!(
+                "Resized window {:?} to {}x{}",
+                window_id, new_size.width, new_size.height
+            );
+        } else {
+            warn!("Received resize for unknown window {:?}", window_id);
+        }
+    }
+
+    fn handle_destroyed(&mut self, event_loop: &ActiveEventLoop) {
+        if self.windows.is_empty() || !self.windows.iter().any(|(_, ctx)| ctx.is_main_window()) {
+            self.windows.clear();
+            debug!("All main windows are closed. Exiting event loop.");
+            event_loop.exit();
+        }
+    }
+}
+
 impl ApplicationHandler for App<'_> {
     fn resumed(&mut self, event_loop: &ActiveEventLoop) {
         if self.windows.is_empty() {
-            let win_attr = Window::default_attributes().with_title("Zenyx");
-            let window = Arc::new(
-                event_loop
-                    .create_window(win_attr)
-                    .expect("create window err."),
-            );
-            let window_id = window.id();
-            let wgpu_ctx = WgpuCtx::new_blocking(window.clone()).unwrap();
-            self.windows.insert(
-                window_id,
-                WindowContext {
-                    window,
-                    ctx: wgpu_ctx,
-                    main_window: true,
-                },
-            );
+            self.create_main_window(event_loop);
         }
     }
 
@@ -56,88 +196,31 @@ impl ApplicationHandler for App<'_> {
     ) {
         match event {
             WindowEvent::CloseRequested => {
-                if let Some(window_context) = self.windows.remove(&window_id) {
-
-                    drop(window_context);
-                    debug!("Window: {:?} closed, exiting", window_id);
-                }
+                self.handle_close_requested(window_id);
             }
             WindowEvent::KeyboardInput {
-                device_id,
-                event,
-                is_synthetic,
-            } => match event.physical_key {
-                winit::keyboard::PhysicalKey::Code(code) => {
-                    if event.state.is_pressed() == false {
-                        return;
-                    }
-                    match code {
-                        winit::keyboard::KeyCode::Space => {
-                            debug!("Space key pressed");
-                            if let Some(window_context) = self.windows.get_mut(&window_id){
-                                match window_context.ctx.bg_color() {
-                                    wgpu::Color::WHITE => {
-                                        window_context.ctx.change_bg_color(wgpu::Color::BLACK)
-                                    }
-                                    wgpu::Color::BLACK => {
-                                        window_context.ctx.change_bg_color(wgpu::Color::WHITE)
-                                    }
-                                    _ => window_context.ctx.change_bg_color(wgpu::Color::WHITE),
-                                }
-                            }
-                        }
-                        winit::keyboard::KeyCode::Escape => {
-                            debug!("Escape key pressed, spawning new window");
-                            let win_attr = Window::default_attributes()
-                                .with_title(format!("Zenyx - New Window {}", self.windows.len()));
-                            let new_window = Arc::new(
-                                event_loop
-                                    .create_window(win_attr)
-                                    .expect("create window err."),
-                            );
-                            let window_id = new_window.id();
-                            let wgpu_ctx = WgpuCtx::new_blocking(new_window.clone()).unwrap();
-                            self.windows.insert(
-                                window_id,
-                                WindowContext {
-                                    window: new_window,
-                                    ctx: wgpu_ctx,
-                                    main_window: false,
-                                },
-                            );
-                        }
-                        _ => info!("Unimplemented keycode: {:?}", code),
-                    }
-                }
-                _ => {}
-            },
-            WindowEvent::RedrawRequested => {
-                if let Some(window_context) = self.windows.get_mut(&window_id) {
-                    window_context.ctx.draw();
-                    window_context.window.request_redraw();
-                }
+                event: key_event, ..
+            } => {
+                self.handle_keyboard_input(event_loop, window_id, key_event);
             }
-            WindowEvent::Resized(size) => {
-                if let Some(window_context) = self.windows.get_mut(&window_id) {
-                    window_context.ctx.resize(size.into());
-                    window_context.window.request_redraw();
-                    let size_str: String = size.height.to_string() + "x" + &size.width.to_string();
-                    debug!("Window resized to {:?}", size_str);
-                }
+            WindowEvent::RedrawRequested => {
+                self.handle_redraw_requested(window_id);
+            }
+            WindowEvent::Resized(new_size) => {
+                self.handle_resize(window_id, new_size);
             }
             WindowEvent::Destroyed => {
-                if  !self.windows.iter().any(|(_,ctx)| ctx.is_main_window()) || self.windows.is_empty() {
-                    self.windows.clear();
-                    event_loop.exit();
-                }
+                self.handle_destroyed(event_loop);
             }
-            _ => trace!("Unhandled window event"),
+            _ => trace!("Unhandled window event for window {:?}", window_id),
         }
     }
 }
 
 pub fn init_renderer(event_loop: EventLoop<()>) {
-    event_loop.set_control_flow(ControlFlow::Poll);
+    event_loop.set_control_flow(ControlFlow::Wait);
     let mut app = App::default();
-    event_loop.run_app(&mut app).unwrap();
+    if let Err(e) = event_loop.run_app(&mut app) {
+        error!("Failed to run application: {:?}", e);
+    }
 }
diff --git a/engine/src/main.rs b/engine/src/main.rs
index 8b0784f..8fddb28 100644
--- a/engine/src/main.rs
+++ b/engine/src/main.rs
@@ -45,7 +45,6 @@ async fn main() -> anyhow::Result<()> {
     info!("Type 'help' for a list of commands.");
 
     core::render::init_renderer(event_loop);
-
     if let Err(_) = repl_thread.join() {
         eprintln!("REPL thread panicked");
     }