diff --git a/lib/rbx_loader/src/rbx.rs b/lib/rbx_loader/src/rbx.rs
index 8742f83..b2214c5 100644
--- a/lib/rbx_loader/src/rbx.rs
+++ b/lib/rbx_loader/src/rbx.rs
@@ -490,9 +490,10 @@ enum Shape{
 	MeshPart,
 	PhysicsData,
 }
-enum MeshAvailability{
+enum MeshAvailability<'a>{
 	Immediate,
-	Deferred(RenderConfigId),
+	DeferredMesh(RenderConfigId),
+	DeferredUnion(RobloxPartDescription,UnionDeferredAttributes<'a>),
 }
 struct DeferredModelDeferredAttributes{
 	render:RenderConfigId,
@@ -504,6 +505,17 @@ struct ModelDeferredAttributes{
 	color:model::Color4,//transparency is in here
 	transform:Planar64Affine3,
 }
+struct DeferredUnionDeferredAttributes<'a>{
+	render:RobloxPartDescription,
+	model:ModelDeferredAttributes,
+	union:UnionDeferredAttributes<'a>,
+}
+#[derive(Hash)]
+struct UnionDeferredAttributes<'a>{
+	asset_id:Option<&'a str>,
+	mesh_data:Option<&'a [u8]>,
+	physics_data:Option<&'a [u8]>,
+}
 struct ModelOwnedAttributes{
 	mesh:model::MeshId,
 	attributes:attr::CollisionAttributes,
@@ -519,12 +531,11 @@ pub fn convert<'a>(
 	dom:&'a rbx_dom_weak::WeakDom,
 	render_config_deferred_loader:&mut RenderConfigDeferredLoader<&'a str>,
 	mesh_deferred_loader:&mut MeshDeferredLoader<&'a str>,
-)->PartialMap1{
+)->PartialMap1<'a>{
 	let mut deferred_models_deferred_attributes=Vec::new();
 	let mut primitive_models_deferred_attributes=Vec::new();
 	let mut primitive_meshes=Vec::new();
 	let mut mesh_id_from_description=HashMap::new();
-	let mut mesh_id_from_physics_data=HashMap::<&[u8],_>::new();
 
 	//just going to leave it like this for now instead of reworking the data structures for this whole thing
 	let textureless_render_group=render_config_deferred_loader.acquire_render_config_id(None);
@@ -705,7 +716,7 @@ pub fn convert<'a>(
 						object.properties.get("TextureID"),
 					){
 						(
-							MeshAvailability::Deferred(render_config_deferred_loader.acquire_render_config_id(Some(texture_asset_id.as_ref()))),
+							MeshAvailability::DeferredMesh(render_config_deferred_loader.acquire_render_config_id(Some(texture_asset_id.as_ref()))),
 							mesh_deferred_loader.acquire_mesh_id(mesh_asset_id.as_ref()),
 						)
 					}else{
@@ -714,37 +725,26 @@ pub fn convert<'a>(
 					Shape::PhysicsData=>{
 						//The union mesh is sized already
 						model_transform=planar64_affine3_from_roblox(cf,&rbx_dom_weak::types::Vector3{x:2.0,y:2.0,z:2.0});
-						if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("PhysicsData"){
-							let physics_data=data.as_ref();
-							let mesh_id=if let Some(&mesh_id)=mesh_id_from_physics_data.get(physics_data){
-								mesh_id
-							}else{
-								match crate::union::convert(physics_data){
-									Ok(mesh)=>{
-										let mesh_id=model::MeshId::new(primitive_meshes.len() as u32);
-										primitive_meshes.push(mesh);
-										mesh_id_from_physics_data.insert(physics_data,mesh_id);
-										mesh_id
-									},
-									Err(e)=>{
-										model_transform=planar64_affine3_from_roblox(cf,size);
-										if !matches!(e,crate::union::Error::Block){
-											println!("Union mesh decode error {e:?}");
-										}
-										*mesh_id_from_description.entry(RobloxBasePartDescription::Part(RobloxPartDescription::default()))
-										.or_insert_with(||{
-											let mesh_id=model::MeshId::new(primitive_meshes.len() as u32);
-											let mesh=primitives::unit_cube(textureless_render_group);
-											primitive_meshes.push(mesh);
-											mesh_id
-										})
-									},
-								}
-							};
-							(MeshAvailability::Immediate,mesh_id)
-						}else{
-							panic!("Mesh has no Mesh or Texture");
+
+						let mut asset_id=None;
+						let mut mesh_data=None;
+						let mut physics_data=None;
+						if let Some(rbx_dom_weak::types::Variant::Content(content))=object.properties.get("AssetId"){
+							asset_id=Some(content.as_ref());
 						}
+						if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("MeshData"){
+							mesh_data=Some(data.as_ref());
+						}
+						if let Some(rbx_dom_weak::types::Variant::BinaryString(data))=object.properties.get("PhysicsData"){
+							physics_data=Some(data.as_ref());
+						}
+						let part_texture_description=get_texture_description(&mut temp_objects,&mut acquire_render_config_id,dom,object,size);
+						let union_deferred_attributes=UnionDeferredAttributes{
+							asset_id,
+							mesh_data,
+							physics_data,
+						};
+						(MeshAvailability::DeferredUnion(part_texture_description,union_deferred_attributes),mesh_id)
 					},
 				};
 				let model_deferred_attributes=ModelDeferredAttributes{
@@ -759,10 +759,15 @@ pub fn convert<'a>(
 				};
 				match availability{
 					MeshAvailability::Immediate=>primitive_models_deferred_attributes.push(model_deferred_attributes),
-					MeshAvailability::Deferred(render)=>deferred_models_deferred_attributes.push(DeferredModelDeferredAttributes{
+					MeshAvailability::DeferredMesh(render)=>deferred_models_deferred_attributes.push(DeferredModelDeferredAttributes{
 						render,
 						model:model_deferred_attributes
 					}),
+					MeshAvailability::DeferredUnion(part_texture_description,union_deferred_attributes)=>deferred_unions_deferred_attributes.push(DeferredUnionDeferredAttributes{
+						render:part_texture_description,
+						model:model_deferred_attributes,
+						union:union_deferred_attributes,
+					}),
 				}
 			}
 		}
@@ -777,10 +782,11 @@ struct MeshWithAabb{
 	mesh:model::Mesh,
 	aabb:strafesnet_common::aabb::Aabb,
 }
-pub struct PartialMap1{
+pub struct PartialMap1<'a>{
 	primitive_meshes:Vec<model::Mesh>,
 	primitive_models_deferred_attributes:Vec<ModelDeferredAttributes>,
 	deferred_models_deferred_attributes:Vec<DeferredModelDeferredAttributes>,
+	deferred_union_deferred_attributes:Vec<DeferredModelDeferredAttributes>,
 }
 impl PartialMap1{
 	pub fn add_meshpart_meshes_and_calculate_attributes(