diff --git a/src/integer.rs b/src/integer.rs
index d5c6879..fb973ab 100644
--- a/src/integer.rs
+++ b/src/integer.rs
@@ -1,6 +1,8 @@
 //integer units
+#[derive(Clone,Copy,Hash,Debug)]
 pub struct Time(i64);
 impl Time{
+	pub const ZERO:Self=Self(0);
 	pub const ONE_SECOND:Self=Self(1_000_000_000);
 	pub const ONE_MILLISECOND:Self=Self(1_000_000);
 	pub const ONE_MICROSECOND:Self=Self(1_000);
@@ -18,6 +20,35 @@ impl Time{
 		Self(Self::ONE_NANOSECOND.0*num)
 	}
 	//should I have checked subtraction? force all time variables to be positive?
+	pub fn nanos(&self)->i64{
+		self.0
+	}
+}
+impl std::fmt::Display for Time{
+	fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
+		write!(f,"{}s+{}ns",self.0/Self::ONE_SECOND.0,self.0%Self::ONE_SECOND.0)
+	}
+}
+impl std::ops::Neg for Time{
+	type Output=Time;
+	#[inline]
+	fn neg(self)->Self::Output {
+		Time(-self.0)
+	}
+}
+impl std::ops::Add<Time> for Time{
+	type Output=Time;
+	#[inline]
+	fn add(self,rhs:Self)->Self::Output {
+		Time(self.0+rhs.0)
+	}
+}
+impl std::ops::Sub<Time> for Time{
+	type Output=Time;
+	#[inline]
+	fn sub(self,rhs:Self)->Self::Output {
+		Time(self.0-rhs.0)
+	}
 }
 
 #[derive(Clone,Copy,Hash)]
diff --git a/src/physics.rs b/src/physics.rs
index dd63374..5fd7b5f 100644
--- a/src/physics.rs
+++ b/src/physics.rs
@@ -1,6 +1,6 @@
 use crate::{instruction::{InstructionEmitter, InstructionConsumer, TimedInstruction}, zeroes::zeroes2};
 
-use crate::integer::{Planar64,Planar64Vec3,Planar64Mat3,Angle32,Angle32Vec2,Ratio64Vec2};
+use crate::integer::{Time,Planar64,Planar64Vec3,Planar64Mat3,Angle32,Ratio64,Ratio64Vec2};
 
 #[derive(Debug)]
 pub enum PhysicsInstruction {
@@ -54,7 +54,7 @@ pub struct Body {
 	position: Planar64Vec3,//I64 where 2^32 = 1 u
 	velocity: Planar64Vec3,//I64 where 2^32 = 1 u/s
 	acceleration: Planar64Vec3,//I64 where 2^32 = 1 u/s/s
-	time: TIME,//nanoseconds x xxxxD!
+	time:Time,//nanoseconds x xxxxD!
 }
 
 pub enum MoveRestriction {
@@ -75,7 +75,7 @@ impl InputState {
 	}
 }
 impl crate::instruction::InstructionEmitter<InputInstruction> for InputState{
-	fn next_instruction(&self, time_limit:crate::body::TIME) -> Option<TimedInstruction<InputInstruction>> {
+	fn next_instruction(&self, time_limit:crate::body::Time) -> Option<TimedInstruction<InputInstruction>> {
 		//this is polled by PhysicsState for actions like Jump
 		//no, it has to be the other way around. physics is run up until the jump instruction, and then the jump instruction is pushed.
 		self.queue.get(0)
@@ -93,24 +93,24 @@ impl crate::instruction::InstructionConsumer<InputInstruction> for InputState{
 #[derive(Clone,Debug)]
 pub struct MouseState {
 	pub pos: glam::IVec2,
-	pub time: TIME,
+	pub time:Time,
 }
 impl Default for MouseState{
 	fn default() -> Self {
 		Self {
-			time:0,
+			time:Time::ZERO,
 			pos:glam::IVec2::ZERO,
 		}
 	}
 }
 impl MouseState {
-	pub fn lerp(&self,target:&MouseState,time:TIME)->glam::IVec2 {
+	pub fn lerp(&self,target:&MouseState,time:Time)->glam::IVec2 {
 		let m0=self.pos.as_i64vec2();
 		let m1=target.pos.as_i64vec2();
 		//these are deltas
-		let t1t=(target.time-time) as i64;
-		let tt0=(time-self.time) as i64;
-		let dt=(target.time-self.time) as i64;
+		let t1t=(target.time-time).nanos();
+		let tt0=(time-self.time).nanos();
+		let dt=(target.time-self.time).nanos();
 		((m0*t1t+m1*tt0)/dt).as_ivec2()
 	}
 }
@@ -121,14 +121,14 @@ pub enum WalkEnum{
 }
 pub struct WalkState {
 	pub target_velocity: Planar64Vec3,
-	pub target_time: TIME,
+	pub target_time: Time,
 	pub state: WalkEnum,
 }
 impl WalkState {
 	pub fn new() -> Self {
 		Self{
 			target_velocity:Planar64Vec3::ZERO,
-			target_time:0,
+			target_time:Time::ZERO,
 			state:WalkEnum::Reached,
 		}
 	}
@@ -160,7 +160,7 @@ impl PhysicsCamera {
 		Self{
 			offset,
 			sensitivity:Ratio64Vec2::ONE.mul_ratio(200_000),
-			mouse:MouseState{pos:glam::IVec2::ZERO,time:-1},//escape initialization hell divide by zero
+			mouse:MouseState{pos:glam::IVec2::ZERO,time:-Time::ONE_NANOSECOND},//escape initialization hell divide by zero
 			clamped_mouse_pos:glam::IVec2::ZERO,
 			angle_pitch_lower_limit:-Angle32::FRAC_PI_2,
 			angle_pitch_upper_limit:Angle32::FRAC_PI_2,
@@ -210,8 +210,7 @@ pub struct StyleModifiers{
 	pub friction:Planar64,
 	pub walk_accel:Planar64,
 	pub gravity:Planar64Vec3,
-	pub strafe_tick_num:TIME,
-	pub strafe_tick_den:TIME,
+	pub strafe_tick_rate:Ratio64,
 	pub hitbox_halfsize:Planar64Vec3,
 }
 impl std::default::Default for StyleModifiers{
@@ -219,8 +218,7 @@ impl std::default::Default for StyleModifiers{
 		Self{
 			controls_mask: !0,//&!(Self::CONTROL_MOVEUP|Self::CONTROL_MOVEDOWN),
 			controls_held: 0,
-			strafe_tick_num: 100,//100t
-			strafe_tick_den: 1_000_000_000,
+			strafe_tick_rate:Ratio64::ONE.div_ratio(100),
 			gravity: Planar64Vec3::new(0,100,0),
 			friction: Planar64::new(12)/10,
 			walk_accel: Planar64::new(90),
@@ -280,7 +278,7 @@ impl StyleModifiers{
 }
 
 pub struct PhysicsState{
-	pub time:TIME,
+	pub time:Time,
 	pub body:Body,
 	pub world:WorldState,//currently there is only one state the world can be in
 	pub game:GameMechanicsState,
@@ -391,26 +389,24 @@ impl RelativeCollision {
 	}
 }
 
-pub type TIME = i64;
-
 impl Body {
 	pub fn with_pva(position:Planar64Vec3,velocity:Planar64Vec3,acceleration:Planar64Vec3) -> Self {
 		Self{
 			position,
 			velocity,
 			acceleration,
-			time: 0,
+			time:Time::ZERO,
 		}
 	}
-	pub fn extrapolated_position(&self,time: TIME)->Planar64Vec3{
-		let dt=(time-self.time) as f64/1_000_000_000f64;
-		self.position+self.velocity*(dt as f32)+self.acceleration*((0.5*dt*dt) as f32)
+	pub fn extrapolated_position(&self,time:Time)->Planar64Vec3{
+		let dt=time-self.time;
+		self.position+self.velocity*dt+self.acceleration*(dt*dt*0.5)
 	}
-	pub fn extrapolated_velocity(&self,time: TIME)->Planar64Vec3{
-		let dt=(time-self.time) as f64/1_000_000_000f64;
-		self.velocity+self.acceleration*(dt as f32)
+	pub fn extrapolated_velocity(&self,time:Time)->Planar64Vec3{
+		let dt=time-self.time;
+		self.velocity+self.acceleration*dt
 	}
-	pub fn advance_time(&mut self, time: TIME){
+	pub fn advance_time(&mut self,time:Time){
 		self.position=self.extrapolated_position(time);
 		self.velocity=self.extrapolated_velocity(time);
 		self.time=time;
@@ -420,9 +416,9 @@ impl Body {
 impl Default for PhysicsState{
 	fn default() -> Self {
  		Self{
-			time: 0,
 			spawn_point:Planar64Vec3::new(0,50,0),
 			body: Body::with_pva(Planar64Vec3::new(0,50,0),Planar64Vec3::new(0,0,0),Planar64Vec3::new(0,-100,0)),
+			time: Time::ZERO,
 			style:StyleModifiers::default(),
 			grounded: false,
 			contacts: std::collections::HashMap::new(),
@@ -628,7 +624,7 @@ impl PhysicsState {
 		}
 	}
 	//tickless gaming
-	pub fn run(&mut self, time_limit:TIME){
+	pub fn run(&mut self, time_limit:Time){
 		//prepare is ommitted - everything is done via instructions.
 		while let Some(instruction) = self.next_instruction(time_limit) {//collect
 			//process
@@ -637,7 +633,7 @@ impl PhysicsState {
 		}
 	}
 
-	pub fn advance_time(&mut self, time: TIME){
+	pub fn advance_time(&mut self, time: Time){
 		self.body.advance_time(time);
 		self.time=time;
 	}
@@ -672,7 +668,7 @@ impl PhysicsState {
 	}
 	fn next_strafe_instruction(&self) -> Option<TimedInstruction<PhysicsInstruction>> {
 		return Some(TimedInstruction{
-			time:(self.time*self.style.strafe_tick_num/self.style.strafe_tick_den+1)*self.style.strafe_tick_den/self.style.strafe_tick_num,
+			time:self.style.strafe_tick_rate.div_int(self.style.strafe_tick_rate.mul_int(self.time)+1),
 			//only poll the physics if there is a before and after mouse event
 			instruction:PhysicsInstruction::StrafeTick
 		});
@@ -727,7 +723,7 @@ impl PhysicsState {
 				let mut a=target_diff/time_delta;
 				self.contact_constrain_acceleration(&mut a);
 				self.body.acceleration=a;
-				self.walk.target_time=self.body.time+((time_delta as f64)*1_000_000_000f64) as TIME;
+				self.walk.target_time=self.body.time+Time::from(time_delta);
 				self.walk.state=WalkEnum::Transient;
 			}
 		}else{
@@ -755,7 +751,7 @@ impl PhysicsState {
 		}
 		aabb
 	}
-	fn predict_collision_end(&self,time:TIME,time_limit:TIME,collision_data:&RelativeCollision) -> Option<TimedInstruction<PhysicsInstruction>> {
+	fn predict_collision_end(&self,time:Time,time_limit:Time,collision_data:&RelativeCollision) -> Option<TimedInstruction<PhysicsInstruction>> {
 		//must treat cancollide false objects differently: you may not exit through the same face you entered.
 		//RelativeCollsion must reference the full model instead of a particular face
 		//this is Ctrl+C Ctrl+V of predict_collision_start but with v=-v before the calc and t=-t after the calc
@@ -773,7 +769,7 @@ impl PhysicsState {
 					//must be moving towards surface to collide
 					//must beat the current soonest collision time
 					//must be moving towards surface
-					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as TIME;
+					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time;
 					if time<=t_time&&t_time<best_time&&0f32<v.x+a.x*-t{
 						//collect valid t
 						best_time=t_time;
@@ -786,7 +782,7 @@ impl PhysicsState {
 					//must be moving towards surface to collide
 					//must beat the current soonest collision time
 					//must be moving towards surface
-					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as TIME;
+					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time;
 					if time<=t_time&&t_time<best_time&&v.x+a.x*-t<0f32{
 						//collect valid t
 						best_time=t_time;
@@ -818,7 +814,7 @@ impl PhysicsState {
 					//must be moving towards surface to collide
 					//must beat the current soonest collision time
 					//must be moving towards surface
-					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as TIME;
+					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time;
 					if time<=t_time&&t_time<best_time&&0f32<v.y+a.y*-t{
 						//collect valid t
 						best_time=t_time;
@@ -831,7 +827,7 @@ impl PhysicsState {
 					//must be moving towards surface to collide
 					//must beat the current soonest collision time
 					//must be moving towards surface
-					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as TIME;
+					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time;
 					if time<=t_time&&t_time<best_time&&v.y+a.y*-t<0f32{
 						//collect valid t
 						best_time=t_time;
@@ -863,7 +859,7 @@ impl PhysicsState {
 					//must be moving towards surface to collide
 					//must beat the current soonest collision time
 					//must be moving towards surface
-					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as TIME;
+					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time;
 					if time<=t_time&&t_time<best_time&&0f32<v.z+a.z*-t{
 						//collect valid t
 						best_time=t_time;
@@ -876,7 +872,7 @@ impl PhysicsState {
 					//must be moving towards surface to collide
 					//must beat the current soonest collision time
 					//must be moving towards surface
-					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as TIME;
+					let t_time=self.body.time+((-t as f64)*1_000_000_000f64) as Time;
 					if time<=t_time&&t_time<best_time&&v.z+a.z*-t<0f32{
 						//collect valid t
 						best_time=t_time;
@@ -909,7 +905,7 @@ impl PhysicsState {
 		}
 		None
 	}
-	fn predict_collision_start(&self,time:TIME,time_limit:TIME,model_id:u32) -> Option<TimedInstruction<PhysicsInstruction>> {
+	fn predict_collision_start(&self,time:Time,time_limit:Time,model_id:u32) -> Option<TimedInstruction<PhysicsInstruction>> {
 		let mesh0=self.mesh();
 		let mesh1=self.models.get(model_id as usize).unwrap().mesh();
 		let (p,v,a,body_time)=(self.body.position,self.body.velocity,self.body.acceleration,self.body.time);
@@ -921,7 +917,7 @@ impl PhysicsState {
 			//must collide now or in the future
 			//must beat the current soonest collision time
 			//must be moving towards surface
-			let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
+			let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
 			if time<=t_time&&t_time<best_time&&0f32<v.x+a.x*t{
 				let dp=self.body.extrapolated_position(t_time)-p;
 				//faces must be overlapping
@@ -937,7 +933,7 @@ impl PhysicsState {
 			//must collide now or in the future
 			//must beat the current soonest collision time
 			//must be moving towards surface
-			let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
+			let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
 			if time<=t_time&&t_time<best_time&&v.x+a.x*t<0f32{
 				let dp=self.body.extrapolated_position(t_time)-p;
 				//faces must be overlapping
@@ -954,7 +950,7 @@ impl PhysicsState {
 			//must collide now or in the future
 			//must beat the current soonest collision time
 			//must be moving towards surface
-			let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
+			let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
 			if time<=t_time&&t_time<best_time&&0f32<v.y+a.y*t{
 				let dp=self.body.extrapolated_position(t_time)-p;
 				//faces must be overlapping
@@ -970,7 +966,7 @@ impl PhysicsState {
 			//must collide now or in the future
 			//must beat the current soonest collision time
 			//must be moving towards surface
-			let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
+			let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
 			if time<=t_time&&t_time<best_time&&v.y+a.y*t<0f32{
 				let dp=self.body.extrapolated_position(t_time)-p;
 				//faces must be overlapping
@@ -987,7 +983,7 @@ impl PhysicsState {
 			//must collide now or in the future
 			//must beat the current soonest collision time
 			//must be moving towards surface
-			let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
+			let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
 			if time<=t_time&&t_time<best_time&&0f32<v.z+a.z*t{
 				let dp=self.body.extrapolated_position(t_time)-p;
 				//faces must be overlapping
@@ -1003,7 +999,7 @@ impl PhysicsState {
 			//must collide now or in the future
 			//must beat the current soonest collision time
 			//must be moving towards surface
-			let t_time=body_time+((t as f64)*1_000_000_000f64) as TIME;
+			let t_time=body_time+((t as f64)*1_000_000_000f64) as Time;
 			if time<=t_time&&t_time<best_time&&v.z+a.z*t<0f32{
 				let dp=self.body.extrapolated_position(t_time)-p;
 				//faces must be overlapping
@@ -1031,7 +1027,7 @@ impl PhysicsState {
 
 impl crate::instruction::InstructionEmitter<PhysicsInstruction> for PhysicsState {
 	//this little next instruction function can cache its return value and invalidate the cached value by watching the State.
-	fn next_instruction(&self,time_limit:TIME) -> Option<TimedInstruction<PhysicsInstruction>> {
+	fn next_instruction(&self,time_limit:Time) -> Option<TimedInstruction<PhysicsInstruction>> {
 		//JUST POLLING!!! NO MUTATION
 		let mut collector = crate::instruction::InstructionCollector::new(time_limit);
 		//check for collision stop instructions with curent contacts