diff --git a/LinearAlgebra/Spherical.cs b/LinearAlgebra/Spherical.cs
index 06ba33d..111a637 100644
--- a/LinearAlgebra/Spherical.cs
+++ b/LinearAlgebra/Spherical.cs
@@ -1,14 +1,13 @@
-namespace Passer.LinearAlgebra
-{
-    public class Spherical
-    {
+using Vector3 = UnityEngine.Vector3;
+
+namespace Passer.LinearAlgebra {
+    public class Spherical {
         public float distance;
         public Direction direction;
 
         public static Spherical zero = new(0, 0, 0);
 
-        public Spherical(float distance, float horizontal, float vertical)
-        {
+        public Spherical(float distance, float horizontal, float vertical) {
             this.distance = distance;
             this.direction = new Direction(horizontal, vertical);
         }
@@ -16,5 +15,22 @@ namespace Passer.LinearAlgebra
             this.distance = distance;
             this.direction = direction;
         }
+
+        public Vector3 ToVector3() {
+            float verticalRad = (UnityEngine.Mathf.PI / 2) - this.direction.vertical * UnityEngine.Mathf.Deg2Rad;
+            float horizontalRad = this.direction.horizontal * UnityEngine.Mathf.Deg2Rad;
+            float cosVertical = UnityEngine.Mathf.Cos(verticalRad);
+            float sinVertical = UnityEngine.Mathf.Sin(verticalRad);
+            float cosHorizontal = UnityEngine.Mathf.Cos(horizontalRad);
+            float sinHorizontal = UnityEngine.Mathf.Sin(horizontalRad);
+
+            float x = this.distance * sinVertical * sinHorizontal;
+            float y = this.distance * cosVertical;
+            float z = this.distance * sinVertical * cosHorizontal;
+
+            Vector3 v = new Vector3(x, y, z);
+            return v;
+
+        }
     }
 }
\ No newline at end of file
diff --git a/Sensors/DistanceSensor.cs b/Sensors/DistanceSensor.cs
new file mode 100644
index 0000000..0845d21
--- /dev/null
+++ b/Sensors/DistanceSensor.cs
@@ -0,0 +1,27 @@
+using System;
+
+namespace Passer.Control.Core {
+
+    public class DistanceSensor : Thing {
+        public float distance = 0;
+
+        public DistanceSensor() : base(true) { }
+
+        public DistanceSensor(byte networkId, byte thingId) : base(null, networkId, thingId, (byte)Type.TemperatureSensor) {
+        }
+
+#if UNITY_5_3_OR_NEWER
+        public override void CreateComponent() {
+            this.component = Unity.DistanceSensor.Create(this.parent);
+            this.component.core = this;
+        }
+#endif        
+
+        public override void ProcessBinary(byte[] bytes) {
+            byte ix = 0;
+            this.distance = LowLevelMessages.ReceiveFloat16(bytes, ref ix);
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/SiteServer.cs b/SiteServer.cs
index 4172a8e..09e3a5f 100644
--- a/SiteServer.cs
+++ b/SiteServer.cs
@@ -22,6 +22,10 @@ namespace Passer.Control.Core {
                 new Tuple<UdpClient, IPEndPoint>(this.udpClient, new(IPAddress.Any, port)));
         }
 
+        public void Close() {
+            this.udpClient.Close();
+        }
+
         public override void Publish() {            
         }
 
diff --git a/Thing.cs b/Thing.cs
index 93bc59a..a4f2958 100644
--- a/Thing.cs
+++ b/Thing.cs
@@ -32,6 +32,7 @@ namespace Passer.Control.Core {
 
         #region Properties
 
+        public RemoteParticipant participant;
         public RemoteParticipant participant;
 
         public delegate void ChangeHandler();
@@ -125,27 +126,29 @@ namespace Passer.Control.Core {
         }
         public Spherical angularVelocity;
 
+#if UNITY_5_3_OR_NEWER
+        public Unity.Thing component;
+#endif
+
         #endregion Properties
 
         #region Init
 
-        public virtual void Init(bool invokeEvent = true) {
-            //Thing.Add(this, invokeEvent);
-        }
+        // public virtual void Init(bool invokeEvent = false) {
+        //     if (invokeEvent)
+        //         InvokeNewThing(this);
+        // }
 
-        public Thing(bool initialize = true) {
-            if (initialize) {
-                //this.Init();
-                //Thing.Add(this);
-            }
-            //OnNewThing?.Invoke(this);
+        public Thing(bool invokeEvent = false) {
+            if (invokeEvent)
+                InvokeNewThing(this);
         }
         public Thing(RemoteParticipant sender, byte networkId, byte thingId, byte thingType = 0) {
             this.participant = sender;
             this.id = thingId;
             this.type = thingType;
             this.networkId = networkId;
-            this.Init();
+            //this.Init();
             //OnNewThing?.Invoke(this);
             //Thing.Add(this);
         }
@@ -199,45 +202,11 @@ namespace Passer.Control.Core {
              OnNewThing?.Invoke(thing);
         }
 
-        // public static void Add(Thing thing, bool invokeEvent = true) {
-        //     Console.WriteLine("added thing");
-        //     Thing foundThing = Get(thing.networkId, thing.id);
-
-        //     if (foundThing == null) {
-        //         if (thing.id == 0)
-        //             thing.id = (byte)(allThings.Count + 1);
-        //         allThings.Add(thing);
-        //         if (invokeEvent)
-        //             OnNewThing?.Invoke(thing);
-        //         Console.Write($"Add thing [{thing.networkId}/{thing.id}] {thing.name}");
-        //     }
-        // }
-
-        // public static Thing Get(byte networkId, byte thingId) {
-        //     Thing thing = allThings.Find(aThing => IsThing(aThing, networkId, thingId));
-        //     return thing;
-        // }
-
         public static bool IsThing(Thing thing, byte networkId, byte thingId) {
             if (thing == null)
                 return false;
             return (thing.networkId == networkId) && (thing.id == thingId);
         }
 
-        // public static void Remove(byte networkId, byte thingId) {
-        //     allThings.RemoveAll(t => t.networkId == networkId && t.id == thingId);
-        // }
-
-        // public static Thing[] GetAllThings() {
-        //     return allThings.ToArray();
-        // }
-
-        // public static void UpdateAll(ulong currentTimeMS) {
-        //     foreach (Thing thing in allThings) {
-        //         if (thing.parent == null) // update only root things
-        //             thing.Update(currentTimeMS);
-        //     }
-        // }
-
     }
 }
diff --git a/Unity/DebugConsole.cs b/Unity/DebugConsole.cs
new file mode 100644
index 0000000..cb4de46
--- /dev/null
+++ b/Unity/DebugConsole.cs
@@ -0,0 +1,25 @@
+#if UNITY_5_3_OR_NEWER
+using System.IO;
+using System.Text;
+using UnityEngine;
+
+namespace Passer.Control.Unity {
+
+    public class UnityLogWriter : TextWriter {
+        public override void Write(char value) {
+            Debug.Log(value);
+        }
+
+        public override void Write(string value) {
+            Debug.Log(value);
+        }
+
+        public override void WriteLine(string value) {
+            Debug.Log(value);
+        }
+
+        public override Encoding Encoding => Encoding.UTF8;
+    }
+    
+}
+#endif
\ No newline at end of file
diff --git a/Unity/DistanceSensor.cs b/Unity/DistanceSensor.cs
new file mode 100644
index 0000000..1b7c9c4
--- /dev/null
+++ b/Unity/DistanceSensor.cs
@@ -0,0 +1,43 @@
+#if UNITY_5_3_OR_NEWER
+using System.Collections;
+using UnityEngine;
+
+namespace Passer.Control.Unity {
+
+    public class DistanceSensor : Thing {
+
+        public new Core.DistanceSensor core {
+            get => (Core.DistanceSensor)base.core; 
+            set => base.core = value;
+        }
+
+        protected virtual void Start() {
+            if (core == null)
+                SetCoreThing(new Core.DistanceSensor());
+
+            StartCoroutine(MeasureDistance());
+        }
+
+        public static DistanceSensor Create(Core.Thing parent) {
+            GameObject distanceObj = new("Distance sensor");
+            DistanceSensor component = distanceObj.AddComponent<DistanceSensor>();
+            if (parent != null && parent.component != null)
+                distanceObj.transform.SetParent(parent.component.transform);
+
+            return component;
+        }
+
+        IEnumerator MeasureDistance() {
+            while (Application.isPlaying) {
+                if (Physics.Raycast(this.transform.position, this.transform.forward, out RaycastHit hitInfo, 10.0f)) {
+                    core.distance = hitInfo.distance;
+
+                    // send distance to...
+                    yield return new WaitForSeconds(1);
+                }
+            }
+        }
+
+    }
+}
+#endif
\ No newline at end of file
diff --git a/Unity/SiteServer.cs b/Unity/SiteServer.cs
new file mode 100644
index 0000000..628ab09
--- /dev/null
+++ b/Unity/SiteServer.cs
@@ -0,0 +1,38 @@
+#if UNITY_5_3_OR_NEWER
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace Passer.Control.Unity {
+
+    public class SiteServer : MonoBehaviour {
+        public Core.SiteServer site;
+
+        public Queue<Core.Thing> thingQueue = new();
+
+        protected virtual void Awake() {
+            Console.SetOut(new UnityLogWriter());
+
+            site = new(7681);
+            Core.Thing.OnNewThing += HandleNewThing;
+        }
+
+        void OnApplicationQuit() {
+            site.Close();
+        }
+
+        public void HandleNewThing(Core.Thing thing) {
+            thingQueue.Enqueue(thing);
+        }
+
+        protected virtual void Update() {
+            site.Update((ulong)(Time.time * 1000));
+            if (thingQueue.TryDequeue(out Core.Thing thing)) {
+                thing.CreateComponent();
+            }
+        }
+
+    }
+
+}
+#endif
\ No newline at end of file
diff --git a/Unity/Thing.cs b/Unity/Thing.cs
new file mode 100644
index 0000000..2687f52
--- /dev/null
+++ b/Unity/Thing.cs
@@ -0,0 +1,38 @@
+#if UNITY_5_3_OR_NEWER
+using UnityEngine;
+
+namespace Passer.Control.Unity {
+
+    public class Thing : MonoBehaviour {
+
+        public Core.Thing core {get; set; }
+
+        protected void SetCoreThing(Core.Thing thing) {
+            core = thing;
+            core.component = this;
+
+            SiteServer siteServer = FindAnyObjectByType<SiteServer>();
+            if (siteServer == null) {
+                Debug.LogWarning("No site server found");
+                return;
+            }
+            siteServer.site.Add(thing);
+        }
+
+        protected virtual void Update() {
+            if (core == null)
+                return;
+
+            if (core.linearVelocity != null) {
+                Vector3 direction = Quaternion.AngleAxis(core.linearVelocity.direction.horizontal, Vector3.up) * Vector3.forward;
+                this.transform.Translate(core.linearVelocity.distance * Time.deltaTime * direction);
+            }
+            if (core.angularVelocity != null) {
+                Vector3 angularVelocity = core.angularVelocity.ToVector3();
+                this.transform.rotation *= Quaternion.Euler(angularVelocity * Time.deltaTime);
+            }
+        }
+    }
+
+}
+#endif
\ No newline at end of file
diff --git a/test/UnitTest1.cs b/test/UnitTest1.cs
index adeb0c0..00fd906 100644
--- a/test/UnitTest1.cs
+++ b/test/UnitTest1.cs
@@ -1,4 +1,5 @@
-using System;
+#if !UNITY_5_3_OR_NEWER
+using System;
 using System.Threading;
 using NUnit.Framework;
 
@@ -83,3 +84,4 @@ namespace ControlCore.test {
         }
     }
 }
+#endif
\ No newline at end of file