diff --git a/src/graphics.rs b/src/graphics.rs
index 448914f..5d4455b 100644
--- a/src/graphics.rs
+++ b/src/graphics.rs
@@ -85,6 +85,14 @@ impl GraphicsCamera{
 		raw
 	}
 }
+impl std::default::Default for GraphicsCamera{
+	fn default()->Self{
+		Self{
+			screen_size:glam::UVec2::ONE,
+			fov:glam::Vec2::ONE,
+		}
+	}
+}
 
 pub struct GraphicsState{
 	pipelines: GraphicsPipelines,
@@ -128,7 +136,7 @@ impl GraphicsState{
 	pub fn load_user_settings(&mut self,user_settings:&crate::settings::UserSettings){
 		self.camera.fov=user_settings.calculate_fov(1.0,&self.camera.screen_size).as_vec2();
 	}
-	fn generate_model_graphics(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,indexed_models:crate::model::IndexedModelInstances){
+	pub fn generate_models(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,indexed_models:crate::model::IndexedModelInstances){
 		//generate texture view per texture
 
 		//idk how to do this gooder lol
@@ -448,7 +456,7 @@ impl GraphicsState{
 		//.into_iter() the modeldata vec so entities can be /moved/ to models.entities
 		let mut model_count=0;
 		let mut instance_count=0;
-		let uniform_buffer_binding_size=crate::graphics_context::required_limits().max_uniform_buffer_binding_size as usize;
+		let uniform_buffer_binding_size=crate::setup::required_limits().max_uniform_buffer_binding_size as usize;
 		let chunk_size=uniform_buffer_binding_size/MODEL_BUFFER_SIZE_BYTES;
 		self.models.reserve(models.len());
 		for model in models.into_iter() {
@@ -521,7 +529,7 @@ impl GraphicsState{
 		println!("Graphics Instances: {}",instance_count);
 	}
 
-	pub fn init(
+	pub fn new(
 		device:&wgpu::Device,
 		queue:&wgpu::Queue,
 		config:&wgpu::SurfaceConfiguration,
@@ -807,14 +815,8 @@ impl GraphicsState{
 			multiview: None,
 		});
 
-		let mut physics = crate::physics::PhysicsState::default();
-
-		physics.load_user_settings(&user_settings);
-
-		let screen_size=glam::uvec2(config.width,config.height);
-
-		let camera=GraphicsCamera::new(screen_size,user_settings.calculate_fov(1.0,&screen_size).as_vec2());
-		let camera_uniforms = camera.to_uniform_data(physics.output().adjust_mouse(&crate::physics::MouseState::default()));
+		let camera=GraphicsCamera::default();
+		let camera_uniforms = camera.to_uniform_data(crate::physics::PhysicsOutputState::default().extrapolate(glam::IVec2::ZERO,crate::integer::Time::ZERO));
 		let camera_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
 			label: Some("Camera"),
 			contents: bytemuck::cast_slice(&camera_uniforms),
@@ -883,8 +885,9 @@ impl GraphicsState{
 		view:&wgpu::TextureView,
 		device:&wgpu::Device,
 		queue:&wgpu::Queue,
-		predicted_time:crate::integer::Time,
 		physics_output:crate::physics::PhysicsOutputState,
+		predicted_time:crate::integer::Time,
+		mouse_pos:glam::IVec2,
 	) {
 		//TODO: use scheduled frame times to create beautiful smoothing simulation physics extrapolation assuming no input
 
@@ -892,7 +895,7 @@ impl GraphicsState{
 			device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
 
 		// update rotation
-		let camera_uniforms = self.camera.to_uniform_data(physics_output.extrapolate(self.global_mouse.lock().clone(),predicted_time));
+		let camera_uniforms = self.camera.to_uniform_data(physics_output.extrapolate(mouse_pos,predicted_time));
 		self.staging_belt
 			.write_buffer(
 				&mut encoder,
diff --git a/src/graphics_worker.rs b/src/graphics_worker.rs
index 6a2dd3c..81e58e1 100644
--- a/src/graphics_worker.rs
+++ b/src/graphics_worker.rs
@@ -1,7 +1,8 @@
 #[derive(Clone)]
-pub enum GraphicsInstruction{
-	Render(crate::physics::PhysicsOutputState,crate::integer::Time),
+pub enum Instruction{
+	Render(crate::physics::PhysicsOutputState,crate::integer::Time,glam::IVec2),
 	//UpdateModel(crate::graphics::ModelUpdate),
+	Resize(winit::dpi::PhysicalSize<u32>),
 }
 
 //Ideally the graphics thread worker description is:
@@ -14,19 +15,25 @@ WorkerDescription{
 //up to three frames in flight, dropping new frame requests when all three are busy, and dropping output frames when one renders out of order
 
 pub fn new(
-		graphics:crate::graphics::GraphicsState,
-		surface:&wgpu::Surface,
+		mut graphics:crate::graphics::GraphicsState,
+		mut config:wgpu::SurfaceConfiguration,
+		surface:wgpu::Surface,
 		device:&wgpu::Device,
 		queue:&wgpu::Queue,
-	)->crate::worker::INWorker<GraphicsInstruction>{
-	crate::worker::INWorker::new(a,move |ins:GraphicsInstruction|{
+	)->crate::compat_worker::INWorker<Instruction>{
+	crate::compat_worker::INWorker::new(move |ins:Instruction|{
 		match ins{
-			GraphicsInstruction::Render(physics_output,predicted_time)=>{
+			Instruction::Resize(size)=>{
+				config.width=size.width.max(1);
+				config.height=size.height.max(1);
+				surface.configure(device,&config);
+			}
+			Instruction::Render(physics_output,predicted_time,mouse_pos)=>{
 				//this has to go deeper somehow
 				let frame=match surface.get_current_texture(){
 					Ok(frame)=>frame,
 					Err(_)=>{
-						surface.configure(device,config);
+						surface.configure(device,&config);
 						surface
 							.get_current_texture()
 							.expect("Failed to acquire next surface texture!")
@@ -37,7 +44,7 @@ pub fn new(
 					..wgpu::TextureViewDescriptor::default()
 				});
 
-				graphics.render(&view,device,queue,physics_output,predicted_time);
+				graphics.render(&view,device,queue,physics_output,predicted_time,mouse_pos);
 
 				frame.present();
 			}
diff --git a/src/integer.rs b/src/integer.rs
index 56c25e2..2c56016 100644
--- a/src/integer.rs
+++ b/src/integer.rs
@@ -41,6 +41,11 @@ impl std::fmt::Display for Time{
 		write!(f,"{}s+{:09}ns",self.0/Self::ONE_SECOND.0,self.0%Self::ONE_SECOND.0)
 	}
 }
+impl std::default::Default for Time{
+	fn default()->Self{
+		Self(0)
+	}
+}
 impl std::ops::Neg for Time{
 	type Output=Time;
 	#[inline]
diff --git a/src/main.rs b/src/main.rs
index ad920d4..cbf1f91 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -119,7 +119,6 @@ pub fn default_models()->model::IndexedModelInstances{
 }
 
 fn main(){
-	let title=format!("Strafe Client v{}",env!("CARGO_PKG_VERSION")).as_str();
-	let context=setup::setup(title);
+	let context=setup::setup(format!("Strafe Client v{}",env!("CARGO_PKG_VERSION")).as_str());
 	context.start();//creates and runs a run context
 }
diff --git a/src/physics.rs b/src/physics.rs
index ec32cad..9aa219d 100644
--- a/src/physics.rs
+++ b/src/physics.rs
@@ -31,9 +31,12 @@ pub enum PhysicsInputInstruction {
 	SetZoom(bool),
 	Reset,
 	Idle,
+		//Idle: there were no input events, but the simulation is safe to advance to this timestep
+		//for interpolation / networking / playback reasons, most playback heads will always want
+		//to be 1 instruction ahead to generate the next state for interpolation.
 }
 
-#[derive(Clone,Hash)]
+#[derive(Clone,Hash,Default)]
 pub struct Body {
 	position: Planar64Vec3,//I64 where 2^32 = 1 u
 	velocity: Planar64Vec3,//I64 where 2^32 = 1 u/s
@@ -241,6 +244,19 @@ impl PhysicsCamera {
 	}
 }
 
+impl std::default::Default for PhysicsCamera{
+	fn default()->Self{
+		Self{
+			offset:Planar64Vec3::ZERO,//TODO: delete this from PhysicsCamera, it should be GraphicsCamera only
+			sensitivity:Ratio64Vec2::ONE*200_000,
+			mouse:MouseState::default(),//t=0 does not cause divide by zero because it's immediately replaced
+			clamped_mouse_pos:glam::IVec2::ZERO,
+			angle_pitch_lower_limit:-Angle32::FRAC_PI_2,
+			angle_pitch_upper_limit:Angle32::FRAC_PI_2,
+		}
+	}
+}
+
 pub struct GameMechanicsState{
 	pub stage_id:u32,
 	//jump_counts:HashMap<u32,u32>,
@@ -527,7 +543,7 @@ pub struct PhysicsState{
 	//This is not the same as Reset which teleports you to Spawn0
 	spawn_point:Planar64Vec3,
 }
-#[derive(Clone)]
+#[derive(Clone,Default)]
 pub struct PhysicsOutputState{
 	camera:PhysicsCamera,
 	body:Body,
diff --git a/src/physics_worker.rs b/src/physics_worker.rs
index 92e7d49..6d06148 100644
--- a/src/physics_worker.rs
+++ b/src/physics_worker.rs
@@ -1,7 +1,6 @@
 use crate::integer::Time;
 use crate::physics::{MouseState,PhysicsInputInstruction};
 use crate::instruction::{TimedInstruction,InstructionConsumer};
-
 #[derive(Debug)]
 pub enum InputInstruction {
 	MoveMouse(glam::IVec2),
@@ -14,52 +13,56 @@ pub enum InputInstruction {
 	Jump(bool),
 	Zoom(bool),
 	Reset,
+}
+pub enum Instruction{
+	Input(InputInstruction),
 	Render,
-		//Idle: there were no input events, but the simulation is safe to advance to this timestep
-		//for interpolation / networking / playback reasons, most playback heads will always want
-		//to be 1 instruction ahead to generate the next state for interpolation.
+	Resize(winit::dpi::PhysicalSize<u32>),
+	//Graphics(crate::graphics_worker::Instruction),
 }
 
-	pub fn new(physics:crate::physics::PhysicsState,graphics_worker:crate::compat_worker::INWorker<crate::graphics_worker::GraphicsInstruction>)->crate::compat_worker::QNWorker<TimedInstruction<InputInstruction>>{
+	pub fn new(mut physics:crate::physics::PhysicsState,mut graphics_worker:crate::compat_worker::INWorker<crate::graphics_worker::Instruction>)->crate::compat_worker::QNWorker<TimedInstruction<Instruction>>{
 		let mut mouse_blocking=true;
 		let mut last_mouse_time=physics.next_mouse.time;
 		let mut timeline=std::collections::VecDeque::new();
-		crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<InputInstruction>|{
-			let mut render=false;
-			if if let Some(phys_input)=match ins.instruction{
-				InputInstruction::MoveMouse(m)=>{
-					if mouse_blocking{
-						//tell the game state which is living in the past about its future
-						timeline.push_front(TimedInstruction{
-							time:last_mouse_time,
-							instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:m}),
-						});
-					}else{
-						//mouse has just started moving again after being still for longer than 10ms.
-						//replace the entire mouse interpolation state to avoid an intermediate state with identical m0.t m1.t timestamps which will divide by zero
-						timeline.push_front(TimedInstruction{
-							time:last_mouse_time,
-							instruction:PhysicsInputInstruction::ReplaceMouse(
-								MouseState{time:last_mouse_time,pos:physics.next_mouse.pos},
-								MouseState{time:ins.time,pos:m}
-							),
-						});
-						//delay physics execution until we have an interpolation target
-						mouse_blocking=true;
-					}
-					last_mouse_time=ins.time;
-					None
+		crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<Instruction>|{
+			if if let Some(phys_input)=match &ins.instruction{
+				Instruction::Input(input_instruction)=>match input_instruction{
+					&InputInstruction::MoveMouse(m)=>{
+						if mouse_blocking{
+							//tell the game state which is living in the past about its future
+							timeline.push_front(TimedInstruction{
+								time:last_mouse_time,
+								instruction:PhysicsInputInstruction::SetNextMouse(MouseState{time:ins.time,pos:m}),
+							});
+						}else{
+							//mouse has just started moving again after being still for longer than 10ms.
+							//replace the entire mouse interpolation state to avoid an intermediate state with identical m0.t m1.t timestamps which will divide by zero
+							timeline.push_front(TimedInstruction{
+								time:last_mouse_time,
+								instruction:PhysicsInputInstruction::ReplaceMouse(
+									MouseState{time:last_mouse_time,pos:physics.next_mouse.pos},
+									MouseState{time:ins.time,pos:m}
+								),
+							});
+							//delay physics execution until we have an interpolation target
+							mouse_blocking=true;
+						}
+						last_mouse_time=ins.time;
+						None
+					},
+					&InputInstruction::MoveForward(s)=>Some(PhysicsInputInstruction::SetMoveForward(s)),
+					&InputInstruction::MoveLeft(s)=>Some(PhysicsInputInstruction::SetMoveLeft(s)),
+					&InputInstruction::MoveBack(s)=>Some(PhysicsInputInstruction::SetMoveBack(s)),
+					&InputInstruction::MoveRight(s)=>Some(PhysicsInputInstruction::SetMoveRight(s)),
+					&InputInstruction::MoveUp(s)=>Some(PhysicsInputInstruction::SetMoveUp(s)),
+					&InputInstruction::MoveDown(s)=>Some(PhysicsInputInstruction::SetMoveDown(s)),
+					&InputInstruction::Jump(s)=>Some(PhysicsInputInstruction::SetJump(s)),
+					&InputInstruction::Zoom(s)=>Some(PhysicsInputInstruction::SetZoom(s)),
+					InputInstruction::Reset=>Some(PhysicsInputInstruction::Reset),
 				},
-				InputInstruction::MoveForward(s)=>Some(PhysicsInputInstruction::SetMoveForward(s)),
-				InputInstruction::MoveLeft(s)=>Some(PhysicsInputInstruction::SetMoveLeft(s)),
-				InputInstruction::MoveBack(s)=>Some(PhysicsInputInstruction::SetMoveBack(s)),
-				InputInstruction::MoveRight(s)=>Some(PhysicsInputInstruction::SetMoveRight(s)),
-				InputInstruction::MoveUp(s)=>Some(PhysicsInputInstruction::SetMoveUp(s)),
-				InputInstruction::MoveDown(s)=>Some(PhysicsInputInstruction::SetMoveDown(s)),
-				InputInstruction::Jump(s)=>Some(PhysicsInputInstruction::SetJump(s)),
-				InputInstruction::Zoom(s)=>Some(PhysicsInputInstruction::SetZoom(s)),
-				InputInstruction::Reset=>Some(PhysicsInputInstruction::Reset),
-				InputInstruction::Render=>{render=true;Some(PhysicsInputInstruction::Idle)},
+				Instruction::Resize(_)=>Some(PhysicsInputInstruction::Idle),
+				Instruction::Render=>Some(PhysicsInputInstruction::Idle),
 			}{
 				//non-mouse event
 				timeline.push_back(TimedInstruction{
@@ -104,8 +107,14 @@ pub enum InputInstruction {
 					});
 				}
 			}
-			if render{
-				graphics_worker.send(crate::graphics_worker::GraphicsInstruction::Render(physics.output(),ins.time));
+			match ins.instruction{
+				Instruction::Render=>{
+					graphics_worker.send(crate::graphics_worker::Instruction::Render(physics.output(),ins.time,physics.next_mouse.pos)).unwrap();
+				},
+				Instruction::Resize(size)=>{
+					graphics_worker.send(crate::graphics_worker::Instruction::Resize(size)).unwrap();
+				},
+				_=>(),
 			}
 		})
 	}
\ No newline at end of file
diff --git a/src/run.rs b/src/run.rs
index 11d0166..01678c5 100644
--- a/src/run.rs
+++ b/src/run.rs
@@ -1,5 +1,5 @@
 use crate::physics::PhysicsInstruction;
-use crate::physics_context::InputInstruction;
+use crate::physics_worker::InputInstruction;
 use crate::instruction::TimedInstruction;
 
 pub enum RunInstruction{
@@ -14,13 +14,18 @@ pub enum RunInstruction{
 struct RunContext{
 	manual_mouse_lock:bool,
 	mouse:crate::physics::MouseState,//std::sync::Arc<std::sync::Mutex<>>
+	device:wgpu::Device,
+	queue:wgpu::Queue,
 	screen_size:glam::UVec2,
 	user_settings:crate::settings::UserSettings,
 	window:winit::window::Window,
-	//physics_thread:crate::worker::QNWorker<TimedInstruction<InputInstruction>>,
+	physics_thread:crate::compat_worker::QNWorker<TimedInstruction<crate::physics_worker::Instruction>>,
 }
 
 impl RunContext{
+	fn get_middle_of_screen(&self)->winit::dpi::PhysicalPosition<f32>{
+		winit::dpi::PhysicalPosition::new(self.screen_size.x as f32/2.0, self.screen_size.y as f32/2.0)
+	}
 	fn window_event(&mut self,time:crate::integer::Time,event: winit::event::WindowEvent) {
 		match event {
 			winit::event::WindowEvent::DroppedFile(path)=>{
@@ -49,7 +54,7 @@ impl RunContext{
 					winit::keyboard::Key::Named(winit::keyboard::NamedKey::Tab)=>{
 						if s{
 							self.manual_mouse_lock=false;
-							match self.window.set_cursor_position(winit::dpi::PhysicalPosition::new(self.screen_size.x as f32/2.0, self.screen_size.y as f32/2.0)){
+							match self.window.set_cursor_position(self.get_middle_of_screen()){
 								Ok(())=>(),
 								Err(e)=>println!("Could not set cursor position: {:?}",e),
 							}
@@ -112,7 +117,7 @@ impl RunContext{
 						}{
 							self.physics_thread.send(TimedInstruction{
 								time,
-								instruction:input_instruction,
+								instruction:crate::physics_worker::Instruction::Input(input_instruction),
 							}).unwrap();
 						}
 					},
@@ -123,13 +128,13 @@ impl RunContext{
 		}
 	}
 
-	fn device_event(&self,time:crate::integer::Time,event: winit::event::DeviceEvent) {
+	fn device_event(&mut self,time:crate::integer::Time,event: winit::event::DeviceEvent) {
 		match event {
 			winit::event::DeviceEvent::MouseMotion {
 			    delta,//these (f64,f64) are integers on my machine
 			} => {
 				if self.manual_mouse_lock{
-					match self.window.set_cursor_position(winit::dpi::PhysicalPosition::new(self.screen_size.x as f32/2.0, self.screen_size.y as f32/2.0)){
+					match self.window.set_cursor_position(self.get_middle_of_screen()){
 						Ok(())=>(),
 						Err(e)=>println!("Could not set cursor position: {:?}",e),
 					}
@@ -141,7 +146,7 @@ impl RunContext{
 				self.mouse.pos+=delta;
 				self.physics_thread.send(TimedInstruction{
 					time,
-					instruction:InputInstruction::MoveMouse(self.mouse.pos),
+					instruction:crate::physics_worker::Instruction::Input(InputInstruction::MoveMouse(self.mouse.pos)),
 				}).unwrap();
 			},
 			winit::event::DeviceEvent::MouseWheel {
@@ -151,7 +156,7 @@ impl RunContext{
 				if false{//self.physics.style.use_scroll{
 					self.physics_thread.send(TimedInstruction{
 						time,
-						instruction:InputInstruction::Jump(true),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
+						instruction:crate::physics_worker::Instruction::Input(InputInstruction::Jump(true)),//activates the immediate jump path, but the style modifier prevents controls&CONTROL_JUMP bit from being set to auto jump
 					}).unwrap();
 				}
 			}
@@ -179,14 +184,14 @@ impl RunContextSetup{
 			None
 		}.unwrap_or(crate::default_models());
 
-		let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue);
-		graphics.load_user_settings(&user_settings);
-		graphics.generate_models(&context.device,&context.queue,indexed_model_instances);
-
 		let mut physics=crate::physics::PhysicsState::default();
 		physics.load_user_settings(&user_settings);
 		physics.generate_models(&indexed_model_instances);
 
+		let mut graphics=crate::graphics::GraphicsState::new(&context.device,&context.queue,&context.config);
+		graphics.load_user_settings(&user_settings);
+		graphics.generate_models(&context.device,&context.queue,indexed_model_instances);
+
 		Self{
 			user_settings,
 			window,
@@ -195,20 +200,25 @@ impl RunContextSetup{
 		}
 	}
 
-	fn into_context(self)->RunContext{
+	fn into_context(self,setup_context:crate::setup::SetupContext)->RunContext{
+		let screen_size=glam::uvec2(setup_context.config.width,setup_context.config.height);
+		let graphics_thread=crate::graphics_worker::new(self.graphics,setup_context.config,setup_context.surface,&setup_context.device,&setup_context.queue);
 		RunContext{
 			manual_mouse_lock:false,
 			mouse:crate::physics::MouseState::default(),
+			//make sure to update this!!!!!
+			screen_size,
+			device:setup_context.device,
+			queue:setup_context.queue,
 			user_settings:self.user_settings,
 			window:self.window,
-			physics:self.physics,
-			graphics:self.graphics,
+			physics_thread:crate::physics_worker::new(self.physics,graphics_thread),
 		}
 	}
 
-	pub fn into_worker(self,setup_context:crate::setup::SetupContext)->crate::worker::QNWorker<TimedInstruction<RunInstruction>>{
-		let run_context=self.into_context();
-		crate::worker::QNWorker::new(move |ins:TimedInstruction<RunInstruction>|{
+	pub fn into_worker(self,setup_context:crate::setup::SetupContext)->crate::compat_worker::QNWorker<TimedInstruction<RunInstruction>>{
+		let mut run_context=self.into_context(setup_context);
+		crate::compat_worker::QNWorker::new(move |ins:TimedInstruction<RunInstruction>|{
 			match ins.instruction{
 				RunInstruction::RequestRedraw=>{
 					run_context.window.request_redraw();
@@ -220,13 +230,20 @@ impl RunContextSetup{
 					run_context.device_event(ins.time,device_event);
 				},
 				RunInstruction::Resize(size)=>{
-					setup_context.config.width=size.width.max(1);
-					setup_context.config.height=size.height.max(1);
-					setup_context.surface.configure(&setup_context.device,&setup_context.config);
-					run_context.physics_thread.send(TimedInstruction{time:ins.time,instruction:PhysicsInstruction::Resize(size)});
+					run_context.physics_thread.send(
+						TimedInstruction{
+							time:ins.time,
+							instruction:crate::physics_worker::Instruction::Resize(size)
+						}
+					).unwrap();
 				}
 				RunInstruction::Render=>{
-					//
+					run_context.physics_thread.send(
+						TimedInstruction{
+							time:ins.time,
+							instruction:crate::physics_worker::Instruction::Render
+						}
+					).unwrap();
 				}
 			}
 		})
diff --git a/src/setup.rs b/src/setup.rs
index 3de933c..f1b0555 100644
--- a/src/setup.rs
+++ b/src/setup.rs
@@ -47,8 +47,8 @@ impl SetupContextPartial1{
 	fn create_surface(self,window:&winit::window::Window)->Result<SetupContextPartial2,wgpu::CreateSurfaceError>{
 		Ok(SetupContextPartial2{
 			backends:self.backends,
+			surface:unsafe{self.instance.create_surface(window)}?,
 			instance:self.instance,
-			surface:unsafe{self.instance.create_surface(window)}?
 		})
 	}
 }
@@ -231,7 +231,7 @@ impl SetupContextSetup{
 
 		let run=crate::run::RunContextSetup::new(&setup_context,window);
 		//the thread that spawns the physics thread
-		let run_thread=run.into_worker(setup_context);
+		let mut run_thread=run.into_worker(setup_context);
 
 		println!("Entering render loop...");
 		let root_time=std::time::Instant::now();