diff --git a/.gitmodules b/.gitmodules
index a17a66b..e364f7d 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -1,3 +1,3 @@
 [submodule "meshcat/viewer"]
 	path = src/meshcat/viewer
-	url = https://github.com/rdeits/meshcat.git
+	url = https://github.com/kingjin94/meshcat.git
diff --git a/setup.py b/setup.py
index fd3fedf..a65ae65 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
 from setuptools import setup, find_packages
 
 setup(name="meshcat",
-    version="0.3.2",
+    version="0.3.2a",
     description="WebGL-based visualizer for 3D geometries and scenes",
     url="https://github.com/rdeits/meshcat-python",
     download_url="https://github.com/rdeits/meshcat-python/archive/v0.3.2.tar.gz",
diff --git a/src/meshcat/geometry.py b/src/meshcat/geometry.py
index ed9109d..664fa7e 100644
--- a/src/meshcat/geometry.py
+++ b/src/meshcat/geometry.py
@@ -294,6 +294,47 @@ def lower(self):
         return data
 
 
+class BillboardObject(Object):
+    def __init__(self, text, base_width, size, global_scale=1, text_color='white', background_color='blue'):
+        """
+
+        :param text: Text to put on the billboard
+        :param base_width: Width of the billboard in pixels
+        :param size: Height of the text in pixels
+        :param global_scale: Scale factor to apply to the billboard (0.01 gets it to roughly meter size)
+        :param text_color: Color name for the text
+        :param background_color: Color name for the background
+        """
+        super(BillboardObject, self).__init__([])
+        self.text = text
+        self.base_width = base_width
+        self.size = size
+        self.global_scale = global_scale
+        self.text_color = text_color
+        self.background_color = background_color
+
+    def lower(self):
+        return {
+            u"metadata": {
+                u"version": 4.5,
+                u"type": u"_billboard",
+            },
+            u"geometries": [],
+            u"materials": [],
+            u"object": {
+                u"uuid": self.uuid,
+                u"type": u"_billboard",
+                u"text": self.text,
+                u"base_width": self.base_width,
+                u"size": self.size,
+                u"global_scale": self.global_scale,
+                u"matrix": np.eye(4).flatten().tolist(),
+                u"text_color": self.text_color,
+                u"background_color": self.background_color,
+            }
+        }
+
+
 class Mesh(Object):
     _type = u"Mesh"
 
diff --git a/src/meshcat/servers/zmqserver.py b/src/meshcat/servers/zmqserver.py
index 3b7e39a..fd28135 100644
--- a/src/meshcat/servers/zmqserver.py
+++ b/src/meshcat/servers/zmqserver.py
@@ -4,6 +4,7 @@
 import base64
 import os
 import re
+import signal
 import sys
 import subprocess
 import multiprocessing
@@ -406,10 +407,21 @@ def main():
     if results.open:
         webbrowser.open(bridge.web_url, new=2)
 
+    def cleanup():
+        bridge.zmq_socket.close()
+        bridge.context.destroy()
+
+    # Make sure also kill results in socket being closed otherwise ZMQbg/Reaper and IO processes might stay open
+    atexit.register(cleanup)
+    signal.signal(signal.SIGTERM, cleanup)
+    signal.signal(signal.SIGINT, cleanup)
+
     try:
         bridge.run()
     except KeyboardInterrupt:
         pass
+    finally:
+        cleanup()
 
 if __name__ == '__main__':
     main()
diff --git a/src/meshcat/viewer b/src/meshcat/viewer
index 65781fc..612b834 160000
--- a/src/meshcat/viewer
+++ b/src/meshcat/viewer
@@ -1 +1 @@
-Subproject commit 65781fcb064db536b99a66fe9fcf5bf0b6d1f790
+Subproject commit 612b834dfe3b928a6e5c3ed81cc06c67b88f9051
diff --git a/src/meshcat/visualizer.py b/src/meshcat/visualizer.py
index b7b9264..7960d31 100644
--- a/src/meshcat/visualizer.py
+++ b/src/meshcat/visualizer.py
@@ -1,3 +1,4 @@
+import signal
 import webbrowser
 import umsgpack
 import numpy as np
@@ -79,6 +80,12 @@ def get_image(self, w, h):
         img = Image.open(io.BytesIO(img_bytes))
         return img
 
+    def close(self):
+        self.zmq_socket.close()
+        self.context.destroy()
+        if self.server_proc is not None:
+            self.server_proc.kill()
+            self.server_proc.wait()
 
 def srcdoc_escape(x):
     return x.replace("&", "&").replace('"', """)