diff --git a/lib/roblox_emulator/src/runner/brickcolor.rs b/lib/roblox_emulator/src/runner/brickcolor.rs
index b864684..00276df 100644
--- a/lib/roblox_emulator/src/runner/brickcolor.rs
+++ b/lib/roblox_emulator/src/runner/brickcolor.rs
@@ -9,15 +9,15 @@ impl BrickColor{
 }
 
 pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
-	let brickcolor_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
-	brickcolor_table.raw_set("new",
+	table.raw_set("new",
 		lua.create_function(|_,name:mlua::String|
 			Ok(BrickColor::from_name(&*name.to_str()?))
 		)?
 	)?;
 
-	globals.set("BrickColor",brickcolor_table)?;
+	globals.set("BrickColor",table)?;
 
 	Ok(())
 }
diff --git a/lib/roblox_emulator/src/runner/cframe.rs b/lib/roblox_emulator/src/runner/cframe.rs
index 10aabac..fa60622 100644
--- a/lib/roblox_emulator/src/runner/cframe.rs
+++ b/lib/roblox_emulator/src/runner/cframe.rs
@@ -1,4 +1,6 @@
-use super::util::coerce_float32;
+use mlua::FromLua;
+
+use super::number::Number;
 use super::vector3::Vector3;
 
 #[derive(Clone,Copy)]
@@ -61,15 +63,15 @@ impl From<rbx_types::CFrame> for CFrame{
 }
 
 pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
-	let cframe_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
 	//CFrame.new
-	cframe_table.raw_set("new",
-		lua.create_function(|_,tuple:(
-			mlua::Value,mlua::Value,Option<f32>,
-			Option<f32>,Option<f32>,Option<f32>,
-			Option<f32>,Option<f32>,Option<f32>,
-			Option<f32>,Option<f32>,Option<f32>,
+	table.raw_set("new",
+		lua.create_function(|lua,tuple:(
+			mlua::Value,mlua::Value,Option<Number>,
+			Option<Number>,Option<Number>,Option<Number>,
+			Option<Number>,Option<Number>,Option<Number>,
+			Option<Number>,Option<Number>,Option<Number>,
 		)|match tuple{
 			//CFrame.new(pos)
 			(
@@ -98,30 +100,30 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 				None,None,None,
 				None,None,None,
 				None,None,None,
-			)=>Ok(CFrame::point(coerce_float32(&x)?,coerce_float32(&y)?,z)),
+			)=>Ok(CFrame::point(Number::from_lua(x,lua)?.into(),Number::from_lua(y,lua)?.into(),z.into())),
 			//CFrame.new(x,y,z,xx,yx,zx,xy,yy,zy,xz,yz,zz)
 			(
-				mlua::Value::Number(x),mlua::Value::Number(y),Some(z),
+				x,y,Some(z),
 				Some(xx),Some(yx),Some(zx),
 				Some(xy),Some(yy),Some(zy),
 				Some(xz),Some(yz),Some(zz),
-			)=>Ok(CFrame::new(x as f32,y as f32,z,
-				xx,yx,zx,
-				xy,yy,zy,
-				xz,yz,zz,
+			)=>Ok(CFrame::new(Number::from_lua(x,lua)?.into(),Number::from_lua(y,lua)?.into(),z.into(),
+				xx.into(),yx.into(),zx.into(),
+				xy.into(),yy.into(),zy.into(),
+				xz.into(),yz.into(),zz.into(),
 			)),
 			_=>Err(mlua::Error::runtime("Invalid arguments"))
 		})?
 	)?;
 
 	//CFrame.Angles
-	cframe_table.raw_set("Angles",
-		lua.create_function(|_,(x,y,z):(f32,f32,f32)|
-			Ok(CFrame::angles(x,y,z))
+	table.raw_set("Angles",
+		lua.create_function(|_,(x,y,z):(Number,Number,Number)|
+			Ok(CFrame::angles(x.into(),y.into(),z.into()))
 		)?
 	)?;
 
-	globals.set("CFrame",cframe_table)?;
+	globals.set("CFrame",table)?;
 
 	Ok(())
 }
diff --git a/lib/roblox_emulator/src/runner/color3.rs b/lib/roblox_emulator/src/runner/color3.rs
index a41aba0..2f1d1e0 100644
--- a/lib/roblox_emulator/src/runner/color3.rs
+++ b/lib/roblox_emulator/src/runner/color3.rs
@@ -1,3 +1,5 @@
+use super::number::Number;
+
 #[derive(Clone,Copy)]
 pub struct Color3{
 	r:f32,
@@ -24,20 +26,20 @@ impl From<Color3> for rbx_types::Color3{
 }
 
 pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
-	let color3_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
-	color3_table.raw_set("new",
-		lua.create_function(|_,(r,g,b):(f32,f32,f32)|
-			Ok(Color3::new(r,g,b))
+	table.raw_set("new",
+		lua.create_function(|_,(r,g,b):(Number,Number,Number)|
+			Ok(Color3::new(r.into(),g.into(),b.into()))
 		)?
 	)?;
-	color3_table.raw_set("fromRGB",
+	table.raw_set("fromRGB",
 		lua.create_function(|_,(r,g,b):(u8,u8,u8)|
 			Ok(Color3::from_rgb(r,g,b))
 		)?
 	)?;
 
-	globals.set("Color3",color3_table)?;
+	globals.set("Color3",table)?;
 
 	Ok(())
 }
diff --git a/lib/roblox_emulator/src/runner/color_sequence.rs b/lib/roblox_emulator/src/runner/color_sequence.rs
index 819fa2e..e5b100c 100644
--- a/lib/roblox_emulator/src/runner/color_sequence.rs
+++ b/lib/roblox_emulator/src/runner/color_sequence.rs
@@ -1,31 +1,30 @@
-#[derive(Clone,Copy)]
-pub struct ColorSequence{}
+#[derive(Clone)]
+pub struct ColorSequence(rbx_types::ColorSequence);
 impl ColorSequence{
-	pub const fn new()->Self{
-		Self{}
+	pub const fn new(keypoints:Vec<rbx_types::ColorSequenceKeypoint>)->Self{
+		Self(rbx_types::ColorSequence{keypoints})
 	}
 }
-impl Into<rbx_types::ColorSequence> for ColorSequence{
-	fn into(self)->rbx_types::ColorSequence{
-		rbx_types::ColorSequence{
-			keypoints:Vec::new()
-		}
+impl From<ColorSequence> for rbx_types::ColorSequence{
+	fn from(value:ColorSequence)->rbx_types::ColorSequence{
+		let ColorSequence(sequence)=value;
+		sequence
 	}
 }
 
 pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
-	let number_sequence_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
-	number_sequence_table.raw_set("new",
+	table.raw_set("new",
 		lua.create_function(|_,_:mlua::MultiValue|
-			Ok(ColorSequence::new())
+			Ok(ColorSequence::new(Vec::new()))
 		)?
 	)?;
 
-	globals.set("ColorSequence",number_sequence_table)?;
+	globals.set("ColorSequence",table)?;
 
 	Ok(())
 }
 
 impl mlua::UserData for ColorSequence{}
-type_from_lua_userdata!(ColorSequence);
+type_from_lua_userdata_clone!(ColorSequence);
diff --git a/lib/roblox_emulator/src/runner/instance/instance.rs b/lib/roblox_emulator/src/runner/instance/instance.rs
index dc084d2..a475de7 100644
--- a/lib/roblox_emulator/src/runner/instance/instance.rs
+++ b/lib/roblox_emulator/src/runner/instance/instance.rs
@@ -5,7 +5,7 @@ use rbx_types::Ref;
 use rbx_dom_weak::{Ustr,InstanceBuilder,WeakDom};
 
 use crate::runner::vector3::Vector3;
-use crate::runner::util::coerce_float32;
+use crate::runner::number::Number;
 
 // disallow non-static lifetimes
 fn static_ustr(s:&'static str)->rbx_dom_weak::Ustr{
@@ -17,10 +17,10 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 	lua.set_app_data(ClassMethodsStore::default());
 	lua.set_app_data(InstanceValueStore::default());
 
-	let instance_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
 	//Instance.new
-	instance_table.raw_set("new",
+	table.raw_set("new",
 		lua.create_function(|lua,(class_name,parent):(mlua::String,Option<Instance>)|{
 			let class_name_str=&*class_name.to_str()?;
 			let parent=parent.unwrap_or(Instance::nil());
@@ -30,7 +30,7 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 		})?
 	)?;
 
-	globals.set("Instance",instance_table)?;
+	globals.set("Instance",table)?;
 
 	Ok(())
 }
@@ -360,7 +360,7 @@ impl mlua::UserData for Instance{
 						rbx_types::Variant::Vector3(typed_value.into())
 					},
 					rbx_reflection::DataType::Value(rbx_types::VariantType::Float32)=>{
-						let typed_value:f32=coerce_float32(&value)?;
+						let typed_value=Number::from_lua(value.clone(),lua)?.to_f32();
 						rbx_types::Variant::Float32(typed_value)
 					},
 					rbx_reflection::DataType::Enum(enum_name)=>{
@@ -368,7 +368,7 @@ impl mlua::UserData for Instance{
 							&mlua::Value::Integer(int)=>Ok(rbx_types::Enum::from_u32(int as u32)),
 							&mlua::Value::Number(num)=>Ok(rbx_types::Enum::from_u32(num as u32)),
 							mlua::Value::String(s)=>{
-								let e=db.enums.get(enum_name).ok_or_else(||mlua::Error::runtime("Database DataType Enum name  does not exist"))?;
+								let e=db.enums.get(enum_name).ok_or_else(||mlua::Error::runtime("Database DataType Enum name does not exist"))?;
 								Ok(rbx_types::Enum::from_u32(*e.items.get(&*s.to_str()?).ok_or_else(||mlua::Error::runtime("Invalid enum item"))?))
 							},
 							mlua::Value::UserData(any_user_data)=>{
@@ -404,8 +404,8 @@ impl mlua::UserData for Instance{
 						rbx_types::Variant::NumberSequence(typed_value.clone().into())
 					},
 					rbx_reflection::DataType::Value(rbx_types::VariantType::ColorSequence)=>{
-						let typed_value:crate::runner::color_sequence::ColorSequence=*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?;
-						rbx_types::Variant::ColorSequence(typed_value.into())
+						let typed_value:&crate::runner::color_sequence::ColorSequence=&*value.as_userdata().ok_or_else(||mlua::Error::runtime("Expected ColorSequence"))?.borrow()?;
+						rbx_types::Variant::ColorSequence(typed_value.clone().into())
 					},
 					rbx_reflection::DataType::Value(rbx_types::VariantType::ContentId)=>{
 						let typed_value=value.as_str().ok_or_else(||mlua::Error::runtime("Expected string"))?.to_owned();
diff --git a/lib/roblox_emulator/src/runner/macros.rs b/lib/roblox_emulator/src/runner/macros.rs
index 6e097ad..c85e097 100644
--- a/lib/roblox_emulator/src/runner/macros.rs
+++ b/lib/roblox_emulator/src/runner/macros.rs
@@ -10,6 +10,18 @@ macro_rules! type_from_lua_userdata{
 		}
 	};
 }
+macro_rules! type_from_lua_userdata_clone{
+	($ty:ident)=>{
+		impl mlua::FromLua for $ty{
+			fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result<Self,mlua::Error>{
+				match value{
+					mlua::Value::UserData(ud)=>Ok(ud.borrow::<Self>()?.clone()),
+					other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!($ty),other))),
+				}
+			}
+		}
+	};
+}
 macro_rules! type_from_lua_userdata_lua_lifetime{
 	($ty:ident)=>{
 		impl mlua::FromLua for $ty<'static>{
diff --git a/lib/roblox_emulator/src/runner/mod.rs b/lib/roblox_emulator/src/runner/mod.rs
index ea8f690..6f71f7e 100644
--- a/lib/roblox_emulator/src/runner/mod.rs
+++ b/lib/roblox_emulator/src/runner/mod.rs
@@ -1,13 +1,13 @@
 #[macro_use]
 mod macros;
 mod runner;
-mod util;
 
 mod r#enum;
 mod udim;
 mod udim2;
 mod color3;
 mod cframe;
+mod number;
 mod vector3;
 mod brickcolor;
 pub mod instance;
diff --git a/lib/roblox_emulator/src/runner/number.rs b/lib/roblox_emulator/src/runner/number.rs
new file mode 100644
index 0000000..7471c27
--- /dev/null
+++ b/lib/roblox_emulator/src/runner/number.rs
@@ -0,0 +1,43 @@
+// the goal of this module is to provide an intermediate type
+// that is guaranteed to be some kind of number, and provide
+// methods to coerce it into various more specific types.
+
+#[derive(Clone,Copy)]
+pub enum Number{
+	Integer(i32),
+	Number(f64),
+}
+macro_rules! impl_ty{
+	($ident:ident,$ty:ty)=>{
+		impl Number{
+			#[inline]
+			pub fn $ident(self)->$ty{
+				match self{
+					Self::Integer(int)=>int as $ty,
+					Self::Number(num)=>num as $ty,
+				}
+			}
+		}
+		impl From<Number> for $ty{
+			fn from(value:Number)->$ty{
+				value.$ident()
+			}
+		}
+	};
+}
+impl_ty!(to_u32,u32);
+impl_ty!(to_i32,i32);
+impl_ty!(to_f32,f32);
+impl_ty!(to_u64,u64);
+impl_ty!(to_i64,i64);
+impl_ty!(to_f64,f64);
+
+impl mlua::FromLua for Number{
+	fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result<Self,mlua::Error>{
+		match value{
+			mlua::Value::Integer(int)=>Ok(Number::Integer(int)),
+			mlua::Value::Number(num)=>Ok(Number::Number(num)),
+			other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!(Number),other))),
+		}
+	}
+}
diff --git a/lib/roblox_emulator/src/runner/number_range.rs b/lib/roblox_emulator/src/runner/number_range.rs
index c46a8ec..d7dcb79 100644
--- a/lib/roblox_emulator/src/runner/number_range.rs
+++ b/lib/roblox_emulator/src/runner/number_range.rs
@@ -1,4 +1,4 @@
-use super::util::coerce_float32;
+use super::number::Number;
 
 #[derive(Clone)]
 pub struct NumberRange(rbx_types::NumberRange);
@@ -18,14 +18,11 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 	let table=lua.create_table()?;
 
 	table.raw_set("new",
-		lua.create_function(|_,(min,max):(mlua::Value,mlua::Value)|{
-			let min=coerce_float32(&min)?;
-			if max.is_nil(){
-				Ok(NumberRange::new(min,min))
-			}else{
-				let max=coerce_float32(&max)?;
-				Ok(NumberRange::new(min,max))
-			}
+		lua.create_function(|_,(min,max):(Number,Option<Number>)|{
+			Ok(match max{
+				Some(max)=>NumberRange::new(min.into(),max.into()),
+				None=>NumberRange::new(min.into(),min.into()),
+			})
 		})?
 	)?;
 
@@ -35,11 +32,4 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 }
 
 impl mlua::UserData for NumberRange{}
-impl mlua::FromLua for NumberRange{
-	fn from_lua(value:mlua::Value,_lua:&mlua::Lua)->Result<Self,mlua::Error>{
-		match value{
-			mlua::Value::UserData(ud)=>Ok(ud.borrow::<Self>()?.clone()),
-			other=>Err(mlua::Error::runtime(format!("Expected {} got {:?}",stringify!(NumberRange),other))),
-		}
-	}
-}
+type_from_lua_userdata_clone!(NumberRange);
diff --git a/lib/roblox_emulator/src/runner/number_sequence.rs b/lib/roblox_emulator/src/runner/number_sequence.rs
index deebb05..f1e910c 100644
--- a/lib/roblox_emulator/src/runner/number_sequence.rs
+++ b/lib/roblox_emulator/src/runner/number_sequence.rs
@@ -13,15 +13,15 @@ impl From<NumberSequence> for rbx_types::NumberSequence{
 }
 
 pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
-	let number_sequence_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
-	number_sequence_table.raw_set("new",
+	table.raw_set("new",
 		lua.create_function(|_,_:mlua::MultiValue|
 			Ok(NumberSequence::new(Vec::new()))
 		)?
 	)?;
 
-	globals.set("NumberSequence",number_sequence_table)?;
+	globals.set("NumberSequence",table)?;
 
 	Ok(())
 }
diff --git a/lib/roblox_emulator/src/runner/udim.rs b/lib/roblox_emulator/src/runner/udim.rs
index 25ae58f..87eda7e 100644
--- a/lib/roblox_emulator/src/runner/udim.rs
+++ b/lib/roblox_emulator/src/runner/udim.rs
@@ -1,3 +1,5 @@
+use super::number::Number;
+
 #[derive(Clone,Copy)]
 pub struct UDim(rbx_types::UDim);
 impl UDim{
@@ -15,8 +17,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 	let table=lua.create_table()?;
 
 	table.raw_set("new",
-		lua.create_function(|_,(scale,offset):(f32,i32)|
-			Ok(UDim::new(scale,offset))
+		lua.create_function(|_,(scale,offset):(Number,i32)|
+			Ok(UDim::new(scale.into(),offset))
 		)?
 	)?;
 
diff --git a/lib/roblox_emulator/src/runner/udim2.rs b/lib/roblox_emulator/src/runner/udim2.rs
index c45cd7a..d0406ae 100644
--- a/lib/roblox_emulator/src/runner/udim2.rs
+++ b/lib/roblox_emulator/src/runner/udim2.rs
@@ -1,4 +1,5 @@
 use super::udim::UDim;
+use super::number::Number;
 
 #[derive(Clone,Copy)]
 pub struct UDim2(rbx_types::UDim2);
@@ -15,8 +16,8 @@ pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
 	let table=lua.create_table()?;
 
 	table.raw_set("new",
-		lua.create_function(|_,(sx,ox,sy,oy):(f32,i32,f32,i32)|
-			Ok(UDim2::new(sx,ox,sy,oy))
+		lua.create_function(|_,(sx,ox,sy,oy):(Number,i32,Number,i32)|
+			Ok(UDim2::new(sx.into(),ox,sy.into(),oy))
 		)?
 	)?;
 
diff --git a/lib/roblox_emulator/src/runner/util.rs b/lib/roblox_emulator/src/runner/util.rs
deleted file mode 100644
index 6e92474..0000000
--- a/lib/roblox_emulator/src/runner/util.rs
+++ /dev/null
@@ -1,7 +0,0 @@
-pub fn coerce_float32(value:&mlua::Value)->mlua::Result<f32>{
-	match value{
-		&mlua::Value::Integer(i)=>Ok(i as f32),
-		&mlua::Value::Number(f)=>Ok(f as f32),
-		_=>Err(mlua::Error::runtime("Expected f32")),
-	}
-}
diff --git a/lib/roblox_emulator/src/runner/vector3.rs b/lib/roblox_emulator/src/runner/vector3.rs
index 7baa91e..3bcb877 100644
--- a/lib/roblox_emulator/src/runner/vector3.rs
+++ b/lib/roblox_emulator/src/runner/vector3.rs
@@ -1,3 +1,5 @@
+use super::number::Number;
+
 #[derive(Clone,Copy)]
 pub struct Vector3(pub(crate)glam::Vec3A);
 
@@ -8,23 +10,24 @@ impl Vector3{
 }
 
 pub fn set_globals(lua:&mlua::Lua,globals:&mlua::Table)->Result<(),mlua::Error>{
-	let vector3_table=lua.create_table()?;
+	let table=lua.create_table()?;
 
 	//Vector3.new
-	vector3_table.raw_set("new",
-		lua.create_function(|_,(x,y,z):(f32,f32,f32)|
-			Ok(Vector3::new(x,y,z))
+	table.raw_set("new",
+		lua.create_function(|_,(x,y,z):(Number,Number,Number)|
+			Ok(Vector3::new(x.into(),y.into(),z.into()))
 		)?
 	)?;
 
-	globals.set("Vector3",vector3_table)?;
+	globals.set("Vector3",table)?;
 
 	Ok(())
 }
 
 impl Into<rbx_types::Vector3> for Vector3{
 	fn into(self)->rbx_types::Vector3{
-		rbx_types::Vector3::new(self.0.x,self.0.y,self.0.z)
+		let Vector3(v)=self;
+		rbx_types::Vector3::new(v.x,v.y,v.z)
 	}
 }