diff --git a/lib/common/src/model.rs b/lib/common/src/model.rs
index 3a9980b..41d981e 100644
--- a/lib/common/src/model.rs
+++ b/lib/common/src/model.rs
@@ -1,3 +1,5 @@
+use std::collections::HashMap;
+
 use crate::integer::{Planar64Vec3,Planar64Affine3};
 use crate::gameplay_attributes;
 
@@ -123,6 +125,87 @@ pub struct Mesh{
 	pub physics_groups:Vec<IndexedPhysicsGroup>,
 }
 
+#[derive(Default)]
+pub struct MeshBuilder{
+	unique_pos:Vec<Planar64Vec3>,//Unit32Vec3
+	unique_normal:Vec<Planar64Vec3>,//Unit32Vec3
+	unique_tex:Vec<TextureCoordinate>,
+	unique_color:Vec<Color4>,
+	unique_vertices:Vec<IndexedVertex>,
+	pos_id_from:HashMap<Planar64Vec3,PositionId>,//Unit32Vec3
+	normal_id_from:HashMap<Planar64Vec3,NormalId>,//Unit32Vec3
+	tex_id_from:HashMap<[u32;2],TextureCoordinateId>,
+	color_id_from:HashMap<[u32;4],ColorId>,
+	vertex_id_from:HashMap<IndexedVertex,VertexId>,
+}
+impl MeshBuilder{
+	pub fn new()->Self{
+		Self::default()
+	}
+	pub fn build(
+		self,
+		polygon_groups:Vec<PolygonGroup>,
+		graphics_groups:Vec<IndexedGraphicsGroup>,
+		physics_groups:Vec<IndexedPhysicsGroup>,
+	)->Mesh{
+		let MeshBuilder{
+			unique_pos,
+			unique_normal,
+			unique_tex,
+			unique_color,
+			unique_vertices,
+			..
+		}=self;
+		Mesh{
+			unique_pos,
+			unique_normal,
+			unique_tex,
+			unique_color,
+			unique_vertices,
+			polygon_groups,
+			graphics_groups,
+			physics_groups,
+		}
+	}
+	pub fn acquire_pos_id(&mut self,pos:Planar64Vec3)->PositionId{
+		*self.pos_id_from.entry(pos).or_insert_with(||{
+			let pos_id=PositionId::new(self.unique_pos.len() as u32);
+			self.unique_pos.push(pos);
+			pos_id
+		})
+	}
+	pub fn acquire_normal_id(&mut self,normal:Planar64Vec3)->NormalId{
+		*self.normal_id_from.entry(normal).or_insert_with(||{
+			let normal_id=NormalId::new(self.unique_normal.len() as u32);
+			self.unique_normal.push(normal);
+			normal_id
+		})
+	}
+	pub fn acquire_tex_id(&mut self,tex:TextureCoordinate)->TextureCoordinateId{
+		let h=tex.to_array().map(f32::to_bits);
+		*self.tex_id_from.entry(h).or_insert_with(||{
+			let tex_id=TextureCoordinateId::new(self.unique_tex.len() as u32);
+			self.unique_tex.push(tex);
+			tex_id
+		})
+	}
+	pub fn acquire_color_id(&mut self,color:Color4)->ColorId{
+		let h=color.to_array().map(f32::to_bits);
+		*self.color_id_from.entry(h).or_insert_with(||{
+			let color_id=ColorId::new(self.unique_color.len() as u32);
+			self.unique_color.push(color);
+			color_id
+		})
+	}
+	pub fn acquire_vertex_id(&mut self,vertex:IndexedVertex)->VertexId{
+		*self.vertex_id_from.entry(vertex.clone()).or_insert_with(||{
+			let vertex_id=VertexId::new(self.unique_vertices.len() as u32);
+			self.unique_vertices.push(vertex);
+			vertex_id
+		})
+	}
+}
+
 #[derive(Debug,Clone,Copy,Hash,id::Id,Eq,PartialEq)]
 pub struct ModelId(u32);
 pub struct Model{