diff --git a/src/body.rs b/src/body.rs
index 64436d92..27ff28c7 100644
--- a/src/body.rs
+++ b/src/body.rs
@@ -16,6 +16,8 @@ pub enum PhysicsInstruction {
 	// 	bool,//true = Trigger; false = teleport
 	// 	bool,//true = Force
 	// )
+	//temp
+	SetPosition(glam::Vec3),
 }
 
 pub struct Body {
@@ -756,6 +758,7 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
 		//selectively update body
 		match &ins.instruction {
 		    PhysicsInstruction::SetWalkTargetVelocity(_)
+		    |PhysicsInstruction::SetPosition(_)
 		    |PhysicsInstruction::SetControlDir(_) => self.time=ins.time,//TODO: queue instructions
 		    PhysicsInstruction::RefreshWalkTarget
 		    |PhysicsInstruction::ReachWalkTargetVelocity
@@ -765,6 +768,15 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
 		    |PhysicsInstruction::Jump => self.advance_time(ins.time),
 		}
 		match ins.instruction {
+			PhysicsInstruction::SetPosition(position)=>{
+				//temp
+				self.body.position=position;
+				//manual clear //for c in self.contacts{process_instruction(CollisionEnd(c))}
+				self.contacts.clear();
+				self.body.acceleration=self.gravity;
+				self.walk.state=WalkEnum::Reached;
+				self.grounded=false;
+			}
 			PhysicsInstruction::CollisionStart(c) => {
 				//check ground
 				match &c.face {
@@ -854,4 +866,4 @@ impl crate::instruction::InstructionConsumer<PhysicsInstruction> for PhysicsStat
 			},
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/src/framework.rs b/src/framework.rs
index b70479e5..b471c22f 100644
--- a/src/framework.rs
+++ b/src/framework.rs
@@ -53,7 +53,7 @@ pub trait Example: 'static + Sized {
 		device: &wgpu::Device,
 		queue: &wgpu::Queue,
 	);
-	fn update(&mut self, device: &wgpu::Device, event: WindowEvent);
+	fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, event: WindowEvent);
 	fn move_mouse(&mut self, delta: (f64,f64));
 	fn render(
 		&mut self,
@@ -369,7 +369,7 @@ fn start<E: Example>(
 					println!("{:#?}", instance.generate_report());
 				}
 				_ => {
-					example.update(&device,event);
+					example.update(&device,&queue,event);
 				}
 			},
 			event::Event::DeviceEvent {
diff --git a/src/load_roblox.rs b/src/load_roblox.rs
index d555879e..0403c070 100644
--- a/src/load_roblox.rs
+++ b/src/load_roblox.rs
@@ -1,3 +1,7 @@
+use crate::model::{ModelData,ModelInstance};
+
+use crate::primitives;
+
 fn class_is_a(class: &str, superclass: &str) -> bool {
 	if class==superclass {
 		return true
@@ -10,16 +14,125 @@ fn class_is_a(class: &str, superclass: &str) -> bool {
 	}
 	return false
 }
-
-pub fn get_objects(dom:rbx_dom_weak::WeakDom, superclass: &str) -> Result<std::vec::Vec<rbx_dom_weak::Instance>, Box<dyn std::error::Error>> {
-	let mut objects = std::vec::Vec::<rbx_dom_weak::Instance>::new();
-	//move matching instances into objects
-	let (_,mut instances) = dom.into_raw();
-	for (_,instance) in instances.drain() {
-		if class_is_a(instance.class.as_str(), superclass) {
-			objects.push(instance);
+fn recursive_collect_superclass(objects: &mut std::vec::Vec<rbx_dom_weak::types::Ref>,dom: &rbx_dom_weak::WeakDom, instance: &rbx_dom_weak::Instance, superclass: &str){
+	for &referent in instance.children() {
+		if let Some(c) = dom.get_by_ref(referent) {
+			if class_is_a(c.class.as_str(), superclass) {
+				objects.push(c.referent());//copy ref
+			}
+			recursive_collect_superclass(objects,dom,c,superclass);
 		}
 	}
-
-	return Ok(objects)
+}
+fn get_texture_refs(dom:&rbx_dom_weak::WeakDom) -> Vec<rbx_dom_weak::types::Ref>{
+	let mut objects = std::vec::Vec::new();
+	recursive_collect_superclass(&mut objects, dom, dom.root(),"Decal");
+	//get ids
+	//clear vec
+	//next class
+	objects
+}
+
+struct RobloxAssetId(u64);
+struct RobloxAssetIdParseErr;
+impl std::str::FromStr for RobloxAssetId {
+    type Err=RobloxAssetIdParseErr;
+    fn from_str(s: &str) -> Result<Self, Self::Err>{
+        let regman=regex::Regex::new(r"(\d+)$").unwrap();
+        if let Some(captures) = regman.captures(s) {
+            if captures.len()==2{//captures[0] is all captures concatenated, and then each individual capture
+                if let Ok(id) = captures[0].parse::<u64>() {
+                    return Ok(Self(id));
+                }
+            }
+        }
+        Err(RobloxAssetIdParseErr)
+    }
+}
+pub fn generate_modeldatas_roblox(dom:rbx_dom_weak::WeakDom) -> Result<(Vec<ModelData>,Vec<String>,glam::Vec3), Box<dyn std::error::Error>>{
+	//ModelData includes texture dds
+	let mut spawn_point=glam::Vec3::ZERO;
+
+	//TODO: generate unit Block, Wedge, etc. after based on part shape lists
+	let mut modeldatas=crate::model::generate_modeldatas(primitives::the_unit_cube_lol(),ModelData::COLOR_FLOATS_WHITE);
+	let unit_cube_modeldata=modeldatas[0].clone();
+
+	let mut texture_id_from_asset_id=std::collections::HashMap::<u64,u32>::new();
+	let mut asset_id_from_texture_id=Vec::new();
+
+	let mut object_refs = std::vec::Vec::new();
+	let mut temp_objects = std::vec::Vec::new();
+	recursive_collect_superclass(&mut object_refs, &dom, dom.root(),"BasePart");
+	for object_ref in object_refs {
+		if let Some(object)=dom.get_by_ref(object_ref){
+			if let (
+					Some(rbx_dom_weak::types::Variant::CFrame(cf)),
+					Some(rbx_dom_weak::types::Variant::Vector3(size)),
+					Some(rbx_dom_weak::types::Variant::Float32(transparency)),
+					Some(rbx_dom_weak::types::Variant::Color3uint8(color3)),
+					Some(rbx_dom_weak::types::Variant::Enum(shape)),
+				) = (
+					object.properties.get("CFrame"),
+					object.properties.get("Size"),
+					object.properties.get("Transparency"),
+					object.properties.get("Color"),
+					object.properties.get("Shape"),//this will also skip unions
+				)
+			{
+				let model_instance=ModelInstance {
+						transform:glam::Mat4::from_translation(
+								glam::Vec3::new(cf.position.x,cf.position.y,cf.position.z)
+							)
+							* glam::Mat4::from_mat3(
+								glam::Mat3::from_cols(
+									glam::Vec3::new(cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x),
+									glam::Vec3::new(cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y),
+									glam::Vec3::new(cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z),
+								),
+							)
+							* glam::Mat4::from_scale(
+								glam::Vec3::new(size.x,size.y,size.z)/2.0
+							),
+						color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
+					};
+				if object.name=="MapStart"{
+					spawn_point=glam::Vec4Swizzles::xyz(model_instance.transform*glam::Vec3::Y.extend(1.0))+glam::vec3(0.0,2.5,0.0);
+					println!("Found MapStart{:?}",spawn_point);
+				}
+				if *transparency==1.0||shape.to_u32()!=1 {
+					continue;
+				}
+				temp_objects.clear();
+				recursive_collect_superclass(&mut temp_objects, &dom, object,"Decal");
+
+				let mut i_can_only_load_one_texture_per_model=None;
+				for &decal_ref in &temp_objects{
+					if let Some(decal)=dom.get_by_ref(decal_ref){
+						if let Some(rbx_dom_weak::types::Variant::Content(content)) = decal.properties.get("Texture") {
+							if let Ok(asset_id)=content.clone().into_string().parse::<RobloxAssetId>(){
+								if let Some(&texture_id)=texture_id_from_asset_id.get(&asset_id.0){
+									i_can_only_load_one_texture_per_model=Some(texture_id);
+								}else{
+									let texture_id=asset_id_from_texture_id.len();
+									texture_id_from_asset_id.insert(asset_id.0,texture_id as u32);
+									asset_id_from_texture_id.push(asset_id.0);
+									//make new model
+									let mut unit_cube_texture=unit_cube_modeldata.clone();
+									unit_cube_texture.texture=Some(texture_id as u32);
+									modeldatas.push(unit_cube_texture);
+								}
+							}
+						}
+					}
+				}
+				match i_can_only_load_one_texture_per_model{
+					//push to existing texture model
+					Some(texture_id)=>modeldatas[(texture_id+1) as usize].instances.push(model_instance),
+					//push instance to big unit cube in the sky
+					None=>modeldatas[0].instances.push(model_instance),
+				}
+			}
+		}
+	}
+	Ok((modeldatas,asset_id_from_texture_id.iter().map(|t|t.to_string()).collect(),spawn_point))
 }
diff --git a/src/main.rs b/src/main.rs
index b6ca2c91..95a5b6b0 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -6,6 +6,7 @@ mod body;
 mod model;
 mod zeroes;
 mod framework;
+mod primitives;
 mod instruction;
 mod load_roblox;
 
@@ -133,7 +134,6 @@ pub struct GraphicsData {
 	models: Vec<ModelGraphics>,
 	depth_view: wgpu::TextureView,
 	staging_belt: wgpu::util::StagingBelt,
-	handy_unit_cube: obj::ObjData,
 }
 
 impl GraphicsData {
@@ -161,51 +161,6 @@ impl GraphicsData {
 		depth_texture.create_view(&wgpu::TextureViewDescriptor::default())
 	}
 
-	fn generate_modeldatas_roblox(&self,dom:rbx_dom_weak::WeakDom) -> Vec<ModelData>{
-		let mut modeldatas=generate_modeldatas(self.handy_unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE);
-		match load_roblox::get_objects(dom, "BasePart") {
-			Ok(objects)=>{
-				for object in objects.iter() {
-					if let (
-							Some(rbx_dom_weak::types::Variant::CFrame(cf)),
-							Some(rbx_dom_weak::types::Variant::Vector3(size)),
-							Some(rbx_dom_weak::types::Variant::Float32(transparency)),
-							Some(rbx_dom_weak::types::Variant::Color3uint8(color3)),
-							Some(rbx_dom_weak::types::Variant::Enum(shape)),
-						) = (
-							object.properties.get("CFrame"),
-							object.properties.get("Size"),
-							object.properties.get("Transparency"),
-							object.properties.get("Color"),
-							object.properties.get("Shape"),//this will also skip unions
-						)
-					{
-						if *transparency==1.0||shape.to_u32()!=1 {
-							continue;
-						}
-						modeldatas[0].instances.push(ModelInstance {
-							transform:glam::Mat4::from_translation(
-									glam::Vec3::new(cf.position.x,cf.position.y,cf.position.z)
-								)
-								* glam::Mat4::from_mat3(
-									glam::Mat3::from_cols(
-										glam::Vec3::new(cf.orientation.x.x,cf.orientation.y.x,cf.orientation.z.x),
-										glam::Vec3::new(cf.orientation.x.y,cf.orientation.y.y,cf.orientation.z.y),
-										glam::Vec3::new(cf.orientation.x.z,cf.orientation.y.z,cf.orientation.z.z),
-									),
-								)
-								* glam::Mat4::from_scale(
-									glam::Vec3::new(size.x,size.y,size.z)/2.0
-								),
-							color: glam::vec4(color3.r as f32/255f32, color3.g as f32/255f32, color3.b as f32/255f32, 1.0-*transparency),
-						})
-					}
-				}
-			},
-			Err(e) => println!("lmao err {:?}", e),
-		}
-		modeldatas
-	}
 	fn generate_model_physics(&mut self,modeldatas:&Vec<ModelData>){
 		self.physics.models.append(&mut modeldatas.iter().map(|m|
 			//make aabb and run vertices to get realistic bounds
@@ -213,59 +168,117 @@ impl GraphicsData {
 		).flatten().collect());
 		println!("Physics Objects: {}",self.physics.models.len());
 	}
-	fn generate_model_graphics(&mut self,device:&wgpu::Device,mut modeldatas:Vec<ModelData>){
+	fn generate_model_graphics(&mut self,device:&wgpu::Device,queue:&wgpu::Queue,mut modeldatas:Vec<ModelData>,textures:Vec<String>){
+		//generate texture view per texture
+
+		//idk how to do this gooder lol
+		let mut double_map=std::collections::HashMap::<u32,u32>::new();
+		let mut texture_views:Vec<wgpu::TextureView>=Vec::with_capacity(textures.len());
+		for (i,t) in textures.iter().enumerate(){
+			if let Ok(mut file) = std::fs::File::open(std::path::Path::new(&format!("textures/{}.dds",t))){
+				let image = ddsfile::Dds::read(&mut file).unwrap();
+
+				let size = wgpu::Extent3d {
+					width: image.get_width()/4*4,//floor(w,4), should be ceil(w,4)
+					height: image.get_height()/4*4,
+					depth_or_array_layers: 1,
+				};
+
+				let layer_size = wgpu::Extent3d {
+					depth_or_array_layers: 1,
+					..size
+				};
+				let max_mips = layer_size.max_mips(wgpu::TextureDimension::D2);
+
+				let texture = device.create_texture_with_data(
+					queue,
+					&wgpu::TextureDescriptor {
+						size,
+						mip_level_count: max_mips,
+						sample_count: 1,
+						dimension: wgpu::TextureDimension::D2,
+						format: wgpu::TextureFormat::Bc7RgbaUnorm,
+						usage: wgpu::TextureUsages::TEXTURE_BINDING | wgpu::TextureUsages::COPY_DST,
+						label: Some(format!("Texture{}",i).as_str()),
+						view_formats: &[],
+					},
+					&image.data,
+				);
+
+				double_map.insert(i as u32, texture_views.len() as u32);
+				texture_views.push(texture.create_view(&wgpu::TextureViewDescriptor {
+					label: Some(format!("Texture{} View",i).as_str()),
+					dimension: Some(wgpu::TextureViewDimension::D2),
+					..wgpu::TextureViewDescriptor::default()
+				}));
+			}
+		}
 		//drain the modeldata vec so entities can be /moved/ to models.entities
 		let mut instance_count=0;
 		self.models.reserve(modeldatas.len());
 		for (i,modeldata) in modeldatas.drain(..).enumerate() {
-			let model_uniforms = get_instances_buffer_data(&modeldata.instances);
-			let model_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
-				label: Some(format!("ModelGraphics{}",i).as_str()),
-				contents: bytemuck::cast_slice(&model_uniforms),
-				usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
-			});
-			let model_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
-				layout: &self.bind_group_layouts.model,
-				entries: &[
-					wgpu::BindGroupEntry {
-						binding: 0,
-						resource: model_buf.as_entire_binding(),
+			let n_instances=modeldata.instances.len();
+			if 0<n_instances{
+				let model_uniforms = get_instances_buffer_data(&modeldata.instances);
+				let model_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+					label: Some(format!("Model{} Buf",i).as_str()),
+					contents: bytemuck::cast_slice(&model_uniforms),
+					usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
+				});
+				let texture_view=match modeldata.texture{
+					Some(texture_id)=>{
+						match double_map.get(&texture_id){
+							Some(&mapped_texture_id)=>&texture_views[mapped_texture_id as usize],
+							None=>&self.temp_squid_texture_view,
+						}
 					},
-					wgpu::BindGroupEntry {
-						binding: 1,
-						resource: wgpu::BindingResource::TextureView(&self.temp_squid_texture_view),
-					},
-					wgpu::BindGroupEntry {
-						binding: 2,
-						resource: wgpu::BindingResource::Sampler(&self.samplers.repeat),
-					},
-				],
-				label: Some(format!("ModelGraphics{}",i).as_str()),
-			});
-			let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
-				label: Some("Vertex"),
-				contents: bytemuck::cast_slice(&modeldata.vertices),
-				usage: wgpu::BufferUsages::VERTEX,
-			});
-			//all of these are being moved here
-			instance_count+=modeldata.instances.len();
-			self.models.push(ModelGraphics{
-				instances:modeldata.instances,
-				vertex_buf,
-				entities: modeldata.entities.iter().map(|indices|{
-					let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
-						label: Some("Index"),
-						contents: bytemuck::cast_slice(&indices),
-						usage: wgpu::BufferUsages::INDEX,
-					});
-					Entity {
-						index_buf,
-						index_count: indices.len() as u32,
-					}
-				}).collect(),
-				bind_group: model_bind_group,
-				model_buf,
-			})
+					None=>&self.temp_squid_texture_view,
+				};
+				let model_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {
+					layout: &self.bind_group_layouts.model,
+					entries: &[
+						wgpu::BindGroupEntry {
+							binding: 0,
+							resource: model_buf.as_entire_binding(),
+						},
+						wgpu::BindGroupEntry {
+							binding: 1,
+							resource: wgpu::BindingResource::TextureView(texture_view),
+						},
+						wgpu::BindGroupEntry {
+							binding: 2,
+							resource: wgpu::BindingResource::Sampler(&self.samplers.repeat),
+						},
+					],
+					label: Some(format!("Model{} Bind Group",i).as_str()),
+				});
+				let vertex_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+					label: Some("Vertex"),
+					contents: bytemuck::cast_slice(&modeldata.vertices),
+					usage: wgpu::BufferUsages::VERTEX,
+				});
+				//all of these are being moved here
+				instance_count+=n_instances;
+				self.models.push(ModelGraphics{
+					instances:modeldata.instances,
+					vertex_buf,
+					entities: modeldata.entities.iter().map(|indices|{
+						let index_buf = device.create_buffer_init(&wgpu::util::BufferInitDescriptor {
+							label: Some("Index"),
+							contents: bytemuck::cast_slice(&indices),
+							usage: wgpu::BufferUsages::INDEX,
+						});
+						Entity {
+							index_buf,
+							index_count: indices.len() as u32,
+						}
+					}).collect(),
+					bind_group: model_bind_group,
+					model_buf,
+				});
+			}else{
+				println!("WARNING: Model{} has 0 instances",i);
+			}
 		}
 		println!("Graphics Objects: {}",self.models.len());
 		println!("Graphics Instances: {}",instance_count);
@@ -284,47 +297,6 @@ fn get_instances_buffer_data(instances:&Vec<ModelInstance>) -> Vec<f32> {
 	raw
 }
 
-fn generate_modeldatas(data:obj::ObjData,color:[f32;4]) -> Vec<ModelData>{
-	let mut modeldatas=Vec::new();
-	let mut vertices = Vec::new();
-	let mut vertex_index = std::collections::HashMap::<obj::IndexTuple,u16>::new();
-	for object in data.objects {
-		vertices.clear();
-		vertex_index.clear();
-		let mut entities = Vec::new();
-		for group in object.groups {
-			let mut indices = Vec::new();
-			for poly in group.polys {
-				for end_index in 2..poly.0.len() {
-					for &index in &[0, end_index - 1, end_index] {
-						let vert = poly.0[index];
-						if let Some(&i)=vertex_index.get(&vert){
-							indices.push(i);
-						}else{
-							let i=vertices.len() as u16;
-							vertices.push(Vertex {
-								pos: data.position[vert.0],
-								texture: data.texture[vert.1.unwrap()],
-								normal: data.normal[vert.2.unwrap()],
-								color,
-							});
-							vertex_index.insert(vert,i);
-							indices.push(i);
-						}
-					}
-				}
-			}
-			entities.push(indices);
-		}
-		modeldatas.push(ModelData {
-			instances: Vec::new(),
-			vertices:vertices.clone(),
-			entities,
-		});
-	}
-	modeldatas
-}
-
 impl framework::Example for GraphicsData {
 	fn optional_features() -> wgpu::Features {
 		wgpu::Features::TEXTURE_COMPRESSION_ASTC
@@ -340,85 +312,12 @@ impl framework::Example for GraphicsData {
 		device: &wgpu::Device,
 		queue: &wgpu::Queue,
 	) -> Self {
-		let unit_cube=obj::ObjData{
-			position: vec![
-				[-1.,-1., 1.],//left bottom back
-				[ 1.,-1., 1.],//right bottom back
-				[ 1., 1., 1.],//right top back
-				[-1., 1., 1.],//left top back
-				[-1., 1.,-1.],//left top front
-				[ 1., 1.,-1.],//right top front
-				[ 1.,-1.,-1.],//right bottom front
-				[-1.,-1.,-1.],//left bottom front
-			],
-			texture: vec![[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]],
-			normal: vec![
-				[1.,0.,0.],//AabbFace::Right
-				[0.,1.,0.],//AabbFace::Top
-				[0.,0.,1.],//AabbFace::Back
-				[-1.,0.,0.],//AabbFace::Left
-				[0.,-1.,0.],//AabbFace::Bottom
-				[0.,0.,-1.],//AabbFace::Front
-			],
-			objects: vec![obj::Object{
-				name: "Unit Cube".to_owned(),
-				groups: vec![obj::Group{
-					name: "Cube Vertices".to_owned(),
-					index: 0,
-					material: None,
-					polys: vec![
-						// back (0, 0, 1)
-						obj::SimplePolygon(vec![
-							obj::IndexTuple(0,Some(0),Some(2)),
-							obj::IndexTuple(1,Some(1),Some(2)),
-							obj::IndexTuple(2,Some(2),Some(2)),
-							obj::IndexTuple(3,Some(3),Some(2)),
-						]),
-						// front (0, 0,-1)
-						obj::SimplePolygon(vec![
-							obj::IndexTuple(4,Some(0),Some(5)),
-							obj::IndexTuple(5,Some(1),Some(5)),
-							obj::IndexTuple(6,Some(2),Some(5)),
-							obj::IndexTuple(7,Some(3),Some(5)),
-						]),
-						// right (1, 0, 0)
-						obj::SimplePolygon(vec![
-							obj::IndexTuple(6,Some(0),Some(0)),
-							obj::IndexTuple(5,Some(1),Some(0)),
-							obj::IndexTuple(2,Some(2),Some(0)),
-							obj::IndexTuple(1,Some(3),Some(0)),
-						]),
-						// left (-1, 0, 0)
-						obj::SimplePolygon(vec![
-							obj::IndexTuple(0,Some(0),Some(3)),
-							obj::IndexTuple(3,Some(1),Some(3)),
-							obj::IndexTuple(4,Some(2),Some(3)),
-							obj::IndexTuple(7,Some(3),Some(3)),
-						]),
-						// top (0, 1, 0)
-						obj::SimplePolygon(vec![
-							obj::IndexTuple(5,Some(1),Some(1)),
-							obj::IndexTuple(4,Some(0),Some(1)),
-							obj::IndexTuple(3,Some(3),Some(1)),
-							obj::IndexTuple(2,Some(2),Some(1)),
-						]),
-						// bottom (0,-1, 0)
-						obj::SimplePolygon(vec![
-							obj::IndexTuple(1,Some(1),Some(4)),
-							obj::IndexTuple(0,Some(0),Some(4)),
-							obj::IndexTuple(7,Some(3),Some(4)),
-							obj::IndexTuple(6,Some(2),Some(4)),
-						]),
-					],
-				}]
-			}],
-			material_libs: Vec::new(),
-		};
+		let unit_cube=primitives::the_unit_cube_lol();
 		let mut modeldatas = Vec::<ModelData>::new();
-		modeldatas.append(&mut generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
-		modeldatas.append(&mut generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
-		modeldatas.append(&mut generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
-		modeldatas.append(&mut generate_modeldatas(unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE));
+		modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teslacyberv3.0.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
+		modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/suzanne.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
+		modeldatas.append(&mut model::generate_modeldatas(obj::ObjData::load_buf(&include_bytes!("../models/teapot.obj")[..]).unwrap(),ModelData::COLOR_FLOATS_WHITE));
+		modeldatas.append(&mut model::generate_modeldatas(unit_cube.clone(),ModelData::COLOR_FLOATS_WHITE));
 		println!("models.len = {:?}", modeldatas.len());
 		modeldatas[0].instances.push(ModelInstance{
 			transform:glam::Mat4::from_translation(glam::vec3(10.,0.,-10.)),
@@ -795,7 +694,6 @@ impl framework::Example for GraphicsData {
 		let depth_view = Self::create_depth_texture(config, device);
 
 		let mut graphics=GraphicsData {
-			handy_unit_cube:unit_cube,
 			start_time: Instant::now(),
 			camera,
 			physics,
@@ -817,13 +715,13 @@ impl framework::Example for GraphicsData {
 		};
 
 		graphics.generate_model_physics(&modeldatas);
-		graphics.generate_model_graphics(&device,modeldatas);
+		graphics.generate_model_graphics(&device,&queue,modeldatas,Vec::new());
 
 		return graphics;
 	}
 
 	#[allow(clippy::single_match)]
-	fn update(&mut self, device: &wgpu::Device, event: winit::event::WindowEvent) {
+	fn update(&mut self, device: &wgpu::Device, queue: &wgpu::Queue, event: winit::event::WindowEvent) {
 		//nothing atm
 		match event {
 			winit::event::WindowEvent::DroppedFile(path) => {
@@ -840,16 +738,16 @@ impl framework::Example for GraphicsData {
 					//.snf = "SNBF"
 					if let (Ok(()),Ok(()))=(std::io::Read::read_exact(&mut input, &mut first_8),std::io::Seek::rewind(&mut input)){
 						//
-						if let Some(modeldatas)={
+						if let Some(Ok((modeldatas,textures,spawn_point)))={
 							if &first_8==b"<roblox!"{
 								if let Ok(dom) = rbx_binary::from_reader(input){
-									Some(self.generate_modeldatas_roblox(dom))
+									Some(load_roblox::generate_modeldatas_roblox(dom))
 								}else{
 									None
 								}
 							}else if &first_8==b"<roblox "{
 								if let Ok(dom) = rbx_xml::from_reader(input,rbx_xml::DecodeOptions::default()){
-									Some(self.generate_modeldatas_roblox(dom))
+									Some(load_roblox::generate_modeldatas_roblox(dom))
 								}else{
 									None
 								}
@@ -863,7 +761,13 @@ impl framework::Example for GraphicsData {
 							self.models.clear();
 							self.physics.models.clear();
 							self.generate_model_physics(&modeldatas);
-							self.generate_model_graphics(device,modeldatas);
+							self.generate_model_graphics(device,queue,modeldatas,textures);
+							//manual reset
+							let time=self.physics.time;
+							instruction::InstructionConsumer::process_instruction(&mut self.physics, instruction::TimedInstruction{
+								time,
+								instruction: body::PhysicsInstruction::SetPosition(spawn_point),
+							})
 						}else{
 							println!("No modeldatas were generated");
 						}
diff --git a/src/model.rs b/src/model.rs
index e2ac139a..99f4c0fc 100644
--- a/src/model.rs
+++ b/src/model.rs
@@ -8,18 +8,63 @@ pub struct Vertex {
 	pub color: [f32; 4],
 }
 
+#[derive(Clone)]
 pub struct ModelInstance {
 	pub transform: glam::Mat4,
 	pub color: glam::Vec4,
 }
 
+#[derive(Clone)]
 pub struct ModelData {
 	pub instances: Vec<ModelInstance>,
 	pub vertices: Vec<Vertex>,
 	pub entities: Vec<Vec<u16>>,
+	pub texture: Option<u32>,
 }
 
 impl ModelData {
 	pub const COLOR_FLOATS_WHITE: [f32;4] = [1.0,1.0,1.0,1.0];
 	pub const COLOR_VEC4_WHITE: glam::Vec4 = glam::vec4(1.0,1.0,1.0,1.0);
+}
+
+pub fn generate_modeldatas(data:obj::ObjData,color:[f32;4]) -> Vec<ModelData>{
+	let mut modeldatas=Vec::new();
+	let mut vertices = Vec::new();
+	let mut vertex_index = std::collections::HashMap::<obj::IndexTuple,u16>::new();
+	for object in data.objects {
+		vertices.clear();
+		vertex_index.clear();
+		let mut entities = Vec::new();
+		for group in object.groups {
+			let mut indices = Vec::new();
+			for poly in group.polys {
+				for end_index in 2..poly.0.len() {
+					for &index in &[0, end_index - 1, end_index] {
+						let vert = poly.0[index];
+						if let Some(&i)=vertex_index.get(&vert){
+							indices.push(i);
+						}else{
+							let i=vertices.len() as u16;
+							vertices.push(Vertex {
+								pos: data.position[vert.0],
+								texture: data.texture[vert.1.unwrap()],
+								normal: data.normal[vert.2.unwrap()],
+								color,
+							});
+							vertex_index.insert(vert,i);
+							indices.push(i);
+						}
+					}
+				}
+			}
+			entities.push(indices);
+		}
+		modeldatas.push(ModelData {
+			instances: Vec::new(),
+			vertices:vertices.clone(),
+			entities,
+			texture: None,
+		});
+	}
+	modeldatas
 }
\ No newline at end of file
diff --git a/src/primitives.rs b/src/primitives.rs
new file mode 100644
index 00000000..a3c86d00
--- /dev/null
+++ b/src/primitives.rs
@@ -0,0 +1,76 @@
+pub fn the_unit_cube_lol() -> obj::ObjData{
+	obj::ObjData{
+		position: vec![
+			[-1.,-1., 1.],//left bottom back
+			[ 1.,-1., 1.],//right bottom back
+			[ 1., 1., 1.],//right top back
+			[-1., 1., 1.],//left top back
+			[-1., 1.,-1.],//left top front
+			[ 1., 1.,-1.],//right top front
+			[ 1.,-1.,-1.],//right bottom front
+			[-1.,-1.,-1.],//left bottom front
+		],
+		texture: vec![[0.0,0.0],[1.0,0.0],[1.0,1.0],[0.0,1.0]],
+		normal: vec![
+			[1.,0.,0.],//AabbFace::Right
+			[0.,1.,0.],//AabbFace::Top
+			[0.,0.,1.],//AabbFace::Back
+			[-1.,0.,0.],//AabbFace::Left
+			[0.,-1.,0.],//AabbFace::Bottom
+			[0.,0.,-1.],//AabbFace::Front
+		],
+		objects: vec![obj::Object{
+			name: "Unit Cube".to_owned(),
+			groups: vec![obj::Group{
+				name: "Cube Vertices".to_owned(),
+				index: 0,
+				material: None,
+				polys: vec![
+					// back (0, 0, 1)
+					obj::SimplePolygon(vec![
+						obj::IndexTuple(0,Some(0),Some(2)),
+						obj::IndexTuple(1,Some(1),Some(2)),
+						obj::IndexTuple(2,Some(2),Some(2)),
+						obj::IndexTuple(3,Some(3),Some(2)),
+					]),
+					// front (0, 0,-1)
+					obj::SimplePolygon(vec![
+						obj::IndexTuple(4,Some(0),Some(5)),
+						obj::IndexTuple(5,Some(1),Some(5)),
+						obj::IndexTuple(6,Some(2),Some(5)),
+						obj::IndexTuple(7,Some(3),Some(5)),
+					]),
+					// right (1, 0, 0)
+					obj::SimplePolygon(vec![
+						obj::IndexTuple(6,Some(0),Some(0)),
+						obj::IndexTuple(5,Some(1),Some(0)),
+						obj::IndexTuple(2,Some(2),Some(0)),
+						obj::IndexTuple(1,Some(3),Some(0)),
+					]),
+					// left (-1, 0, 0)
+					obj::SimplePolygon(vec![
+						obj::IndexTuple(0,Some(0),Some(3)),
+						obj::IndexTuple(3,Some(1),Some(3)),
+						obj::IndexTuple(4,Some(2),Some(3)),
+						obj::IndexTuple(7,Some(3),Some(3)),
+					]),
+					// top (0, 1, 0)
+					obj::SimplePolygon(vec![
+						obj::IndexTuple(5,Some(1),Some(1)),
+						obj::IndexTuple(4,Some(0),Some(1)),
+						obj::IndexTuple(3,Some(3),Some(1)),
+						obj::IndexTuple(2,Some(2),Some(1)),
+					]),
+					// bottom (0,-1, 0)
+					obj::SimplePolygon(vec![
+						obj::IndexTuple(1,Some(1),Some(4)),
+						obj::IndexTuple(0,Some(0),Some(4)),
+						obj::IndexTuple(7,Some(3),Some(4)),
+						obj::IndexTuple(6,Some(2),Some(4)),
+					]),
+				],
+			}]
+		}],
+		material_libs: Vec::new(),
+	}
+}
\ No newline at end of file