diff --git a/punyverse/assets/textures.txt b/punyverse/assets/textures.txt
index b9d7361..1e01337 100644
--- a/punyverse/assets/textures.txt
+++ b/punyverse/assets/textures.txt
@@ -11,7 +11,12 @@ moon.jpg
 mars.jpg
 jupiter.jpg
 saturn.jpg
-sky.jpg
+sky_px.jpg
+sky_py.jpg
+sky_pz.jpg
+sky_nx.jpg
+sky_ny.jpg
+sky_nz.jpg
 moons/io.jpg
 moons/europa.jpg
 moons/ganymede.jpg
diff --git a/punyverse/assets/textures/constellation_nx.png b/punyverse/assets/textures/constellation_nx.png
new file mode 100644
index 0000000..1dabc48
Binary files /dev/null and b/punyverse/assets/textures/constellation_nx.png differ
diff --git a/punyverse/assets/textures/constellation_ny.png b/punyverse/assets/textures/constellation_ny.png
new file mode 100644
index 0000000..db24a25
Binary files /dev/null and b/punyverse/assets/textures/constellation_ny.png differ
diff --git a/punyverse/assets/textures/constellation_nz.png b/punyverse/assets/textures/constellation_nz.png
new file mode 100644
index 0000000..16f4570
Binary files /dev/null and b/punyverse/assets/textures/constellation_nz.png differ
diff --git a/punyverse/assets/textures/constellation_px.png b/punyverse/assets/textures/constellation_px.png
new file mode 100644
index 0000000..65b5ccf
Binary files /dev/null and b/punyverse/assets/textures/constellation_px.png differ
diff --git a/punyverse/assets/textures/constellation_py.png b/punyverse/assets/textures/constellation_py.png
new file mode 100644
index 0000000..587f9d7
Binary files /dev/null and b/punyverse/assets/textures/constellation_py.png differ
diff --git a/punyverse/assets/textures/constellation_pz.png b/punyverse/assets/textures/constellation_pz.png
new file mode 100644
index 0000000..a52c2c0
Binary files /dev/null and b/punyverse/assets/textures/constellation_pz.png differ
diff --git a/punyverse/assets/textures/sky.jpg b/punyverse/assets/textures/sky.jpg
deleted file mode 100644
index 6f96f29..0000000
Binary files a/punyverse/assets/textures/sky.jpg and /dev/null differ
diff --git a/punyverse/assets/textures/sky_nx.jpg b/punyverse/assets/textures/sky_nx.jpg
new file mode 100644
index 0000000..d251612
Binary files /dev/null and b/punyverse/assets/textures/sky_nx.jpg differ
diff --git a/punyverse/assets/textures/sky_ny.jpg b/punyverse/assets/textures/sky_ny.jpg
new file mode 100644
index 0000000..507b8fd
Binary files /dev/null and b/punyverse/assets/textures/sky_ny.jpg differ
diff --git a/punyverse/assets/textures/sky_nz.jpg b/punyverse/assets/textures/sky_nz.jpg
new file mode 100644
index 0000000..3c6e447
Binary files /dev/null and b/punyverse/assets/textures/sky_nz.jpg differ
diff --git a/punyverse/assets/textures/sky_px.jpg b/punyverse/assets/textures/sky_px.jpg
new file mode 100644
index 0000000..5a20011
Binary files /dev/null and b/punyverse/assets/textures/sky_px.jpg differ
diff --git a/punyverse/assets/textures/sky_py.jpg b/punyverse/assets/textures/sky_py.jpg
new file mode 100644
index 0000000..b52f823
Binary files /dev/null and b/punyverse/assets/textures/sky_py.jpg differ
diff --git a/punyverse/assets/textures/sky_pz.jpg b/punyverse/assets/textures/sky_pz.jpg
new file mode 100644
index 0000000..3463c28
Binary files /dev/null and b/punyverse/assets/textures/sky_pz.jpg differ
diff --git a/punyverse/entity.py b/punyverse/entity.py
index 02e566e..59abb27 100644
--- a/punyverse/entity.py
+++ b/punyverse/entity.py
@@ -5,10 +5,10 @@ from pyglet.gl import *
 # noinspection PyUnresolvedReferences
 from six.moves import range
 
-from punyverse.glgeom import compile, glRestore, belt, Disk, OrbitVBO, Matrix4f, SimpleSphere, TangentSphere
+from punyverse.glgeom import compile, glRestore, belt, Disk, OrbitVBO, Matrix4f, SimpleSphere, TangentSphere, Cube
 from punyverse.model import load_model, WavefrontVBO
 from punyverse.orbit import KeplerOrbit
-from punyverse.texture import get_best_texture, load_clouds
+from punyverse.texture import get_best_texture, load_clouds, get_cube_map
 from punyverse.utils import cached_property
 
 G = 6.67384e-11  # Gravitation Constant
@@ -126,11 +126,11 @@ class Sky(Entity):
         yaw = world.evaluate(info.get('yaw', 0))
         roll = world.evaluate(info.get('roll', 0))
 
-        super(Sky, self).__init__(world, 'Sky', (0, 0, 0), (pitch, yaw, roll))
+        super(Sky, self).__init__(world, 'Sky', (0, 0, 0), [pitch, yaw, roll])
 
-        self.texture = get_best_texture(info['texture'])
-        division = info.get('division', 30)
-        self.sphere = SimpleSphere(division, division)
+        self.texture = get_best_texture(info['texture'], loader=get_cube_map)
+        self.constellation = get_cube_map(info['constellation'])
+        self.cube = Cube()
 
     def draw(self, options):
         cam = self.world.cam
@@ -140,16 +140,20 @@ class Sky(Entity):
                             Matrix4f.from_angles(rotation=self.rotation))
 
         glActiveTexture(GL_TEXTURE0)
-        glBindTexture(GL_TEXTURE_2D, self.texture)
+        glBindTexture(GL_TEXTURE_CUBE_MAP, self.texture)
         shader.uniform_texture('u_skysphere', 0)
 
-        glBindBuffer(GL_ARRAY_BUFFER, self.sphere.vbo)
-        shader.vertex_attribute('a_direction', self.sphere.direction_size, self.sphere.type, GL_FALSE,
-                                self.sphere.stride, self.sphere.direction_offset)
-        shader.vertex_attribute('a_uv', self.sphere.uv_size, self.sphere.type, GL_FALSE,
-                                self.sphere.stride, self.sphere.uv_offset)
+        glActiveTexture(GL_TEXTURE1)
+        glBindTexture(GL_TEXTURE_CUBE_MAP, self.constellation)
+        shader.uniform_texture('u_constellation', 1)
 
-        glDrawArrays(GL_TRIANGLE_STRIP, 0, self.sphere.vertex_count)
+        shader.uniform_bool('u_lines', options.constellations)
+
+        glBindBuffer(GL_ARRAY_BUFFER, self.cube.vbo)
+        shader.vertex_attribute('a_direction', self.cube.direction_size, self.cube.type, GL_FALSE,
+                                self.cube.stride, self.cube.direction_offset)
+
+        glDrawArrays(GL_TRIANGLES, 0, self.cube.vertex_count)
 
         shader.deactivate_attributes()
         glBindBuffer(GL_ARRAY_BUFFER, 0)
diff --git a/punyverse/glgeom.py b/punyverse/glgeom.py
index 952e10b..ab1003e 100644
--- a/punyverse/glgeom.py
+++ b/punyverse/glgeom.py
@@ -283,6 +283,22 @@ class TangentSphere(object):
         self.vbo = array_to_gl_buffer(buffer)
 
 
+class Cube(object):
+    type = GL_SHORT
+    stride = 3 * 2
+    direction_offset = 0
+    direction_size = 3
+    vertex_count = 36
+
+    def __init__(self):
+        self.vbo = array_to_gl_buffer([
+            -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1,
+            -1, -1, 1, 1, -1, -1, 1, 1, -1, -1, 1, -1, 1, 1, 1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, -1, -1, 1, -1, 1, 1, 1,
+            1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1, -1, -1, -1, -1,
+            -1, -1, 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, 1, -1, 1
+        ], 'h')
+
+
 class OrbitVBO(object):
     def __init__(self, orbit):
         buffer = 360 * 3 * [0]
diff --git a/punyverse/shaders/sky.fragment.glsl b/punyverse/shaders/sky.fragment.glsl
index 1821625..d65e402 100644
--- a/punyverse/shaders/sky.fragment.glsl
+++ b/punyverse/shaders/sky.fragment.glsl
@@ -1,9 +1,13 @@
 #version 130
 
-in vec2 v_uv;
+in vec3 v_direction;
 out vec4 o_fragColor;
-uniform sampler2D u_skysphere;
+uniform bool u_lines;
+uniform samplerCube u_skysphere;
+uniform samplerCube u_constellation;
 
 void main() {
-    o_fragColor = vec4(texture(u_skysphere, vec2(1 - v_uv.s, v_uv.t)).rgb, 1);
+    o_fragColor = texture(u_skysphere, v_direction);
+    if (u_lines)
+        o_fragColor += texture(u_constellation, v_direction);
 }
diff --git a/punyverse/shaders/sky.vertex.glsl b/punyverse/shaders/sky.vertex.glsl
index 075207e..890cc28 100644
--- a/punyverse/shaders/sky.vertex.glsl
+++ b/punyverse/shaders/sky.vertex.glsl
@@ -1,11 +1,10 @@
 #version 130
 
 in vec3 a_direction;
-in vec2 a_uv;
-out vec2 v_uv;
+out vec3 v_direction;
 uniform mat4 u_mvpMatrix;
 
 void main() {
     gl_Position = (u_mvpMatrix * vec4(a_direction, 1)).xyww;
-    v_uv = a_uv;
+    v_direction = a_direction;
 }
diff --git a/punyverse/texture.py b/punyverse/texture.py
index b74512a..d4f8c4a 100644
--- a/punyverse/texture.py
+++ b/punyverse/texture.py
@@ -2,7 +2,7 @@ from __future__ import print_function
 
 import os.path
 import struct
-from ctypes import c_int, byref, c_uint
+from ctypes import c_int, byref
 from io import BytesIO
 
 import six
@@ -42,7 +42,7 @@ except ImportError:
             result[y1 * row:y1 * row + row] = source[y2 * row:y2 * row + row]
         return six.binary_type(result)
 
-__all__ = ['load_texture', 'load_clouds', 'load_image', 'get_best_texture', 'max_texture_size']
+__all__ = ['load_texture', 'load_clouds', 'load_image', 'get_best_texture', 'max_texture_size', 'get_cube_map']
 
 id = 0
 cache = {}
@@ -177,31 +177,30 @@ def load_image(file, path):
     return path, width, height, len(raw.format), mode, flip_vertical(texture, width, height)
 
 
-def load_texture(file, clamp=False):
+def get_file_path(file):
     if os.path.isabs(file):
         path = file
         file = os.path.basename(path)
     else:
         path = os.path.join(os.path.dirname(__file__), 'assets', 'textures', file)
+    return path, file
 
+
+def load_texture(file, clamp=False):
+    path, file = get_file_path(file)
     if path in cache:
         return cache[path]
 
     path, width, height, depth, mode, texture = load_image(file, path)
 
-    buffer = c_uint()
+    buffer = GLuint()
     glGenTextures(1, byref(buffer))
     id = buffer.value
 
     glBindTexture(GL_TEXTURE_2D, id)
 
     if gl_info.have_version(3) or gl_info.have_extension('GL_ARB_framebuffer_object'):
-        glTexImage2D(GL_TEXTURE_2D, 0, {
-            GL_RGB: GL_RGB8,
-            GL_BGR: GL_RGB8,
-            GL_RGBA: GL_RGBA8,
-            GL_BGRA: GL_RGBA8,
-        }[mode], width, height, 0, mode, GL_UNSIGNED_BYTE, texture)
+        glTexImage2D(GL_TEXTURE_2D, 0, get_internal_mode(mode), width, height, 0, mode, GL_UNSIGNED_BYTE, texture)
         glGenerateMipmap(GL_TEXTURE_2D)
     else:
         gluBuild2DMipmaps(GL_TEXTURE_2D, depth, width, height, mode, GL_UNSIGNED_BYTE, texture)
@@ -220,13 +219,17 @@ def load_texture(file, clamp=False):
     return id
 
 
-def load_clouds(file):
-    if os.path.isabs(file):
-        path = file
-        file = os.path.basename(path)
-    else:
-        path = os.path.join(os.path.dirname(__file__), 'assets', 'textures', file)
+def get_internal_mode(mode):
+    return {
+        GL_RGB: GL_RGB8,
+        GL_BGR: GL_RGB8,
+        GL_RGBA: GL_RGBA8,
+        GL_BGRA: GL_RGBA8,
+    }[mode]
 
+
+def load_clouds(file):
+    path, file = get_file_path(file)
     if path in cache:
         return cache[path]
 
@@ -235,7 +238,7 @@ def load_clouds(file):
     if depth != 1:
         texture = texture[::depth]
 
-    buffer = c_uint()
+    buffer = GLuint()
     glGenTextures(1, byref(buffer))
     id = buffer.value
 
@@ -257,6 +260,35 @@ def load_clouds(file):
     return id
 
 
+def get_cube_map(files):
+    assert len(files) == 6
+
+    buffer = GLuint()
+    glGenTextures(1, byref(buffer))
+    id = buffer.value
+
+    glBindTexture(GL_TEXTURE_CUBE_MAP, id)
+    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_BASE_LEVEL, 0)
+    glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 0)
+    for file, part in zip(files, [
+        GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+        GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+        GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+        GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+        GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+        GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+    ]):
+        try:
+            path, file = get_file_path(file)
+            path, width, height, depth, mode, texture = load_image(file, path)
+        except Exception:
+            glDeleteTextures(1, byref(buffer))
+            raise
+        glTexImage2D(part, 0, get_internal_mode(mode), width, height, 0, mode, GL_UNSIGNED_BYTE, texture)
+
+    return id
+
+
 def get_best_texture(info, loader=load_texture, optional=False, **kwargs):
     if isinstance(info, list):
         for item in info:
diff --git a/punyverse/ui.py b/punyverse/ui.py
index a78de86..4b35521 100644
--- a/punyverse/ui.py
+++ b/punyverse/ui.py
@@ -38,6 +38,7 @@ class Punyverse(pyglet.window.Window):
         self.info_precise = False
         self.atmosphere = True
         self.cloud = True
+        self.constellations = False
 
         self.ticks = [
             1, 2, 5, 10, 20, 40, 60,  # Second range
@@ -104,6 +105,7 @@ class Punyverse(pyglet.window.Window):
             key.P: attribute_toggler(self, 'info_precise'),
             key.C: attribute_toggler(self, 'cloud'),
             key.X: attribute_toggler(self, 'atmosphere'),
+            key.L: attribute_toggler(self, 'constellations'),
             key.ENTER: attribute_toggler(self, 'running'),
             key.INSERT: increment_tick,
             key.DELETE: decrement_tick,
diff --git a/punyverse/world.json b/punyverse/world.json
index db6b2a6..0fac145 100644
--- a/punyverse/world.json
+++ b/punyverse/world.json
@@ -299,12 +299,17 @@
     }
   },
   "sky": {
-    "texture": ["sky.jpg", "sky_large.jpg", "sky_medium.jpg", "sky_small.jpg"],
+    "texture": [
+      ["sky_px.jpg", "sky_nx.jpg", "sky_py.jpg", "sky_ny.jpg", "sky_pz.jpg", "sky_nz.jpg"]
+    ],
+    "constellation": [
+      "constellation_px.png", "constellation_nx.png", "constellation_py.png",
+      "constellation_ny.png", "constellation_pz.png", "constellation_nz.png"
+    ],
     "rotation": 0,
     "division": 30,
-    "pitch": -150.19,
-    "yaw": 0,
-    "roll": 0
+    "pitch": -119.3,
+    "yaw": -97
   },
   "asteroids": ["asteroids/01.obj", "asteroids/02.obj", "asteroids/03.obj"],
   "start": {