diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 2628c2d..09b5d97 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -7,13 +7,19 @@ cmake_minimum_required (VERSION 3.8)
 add_executable(solver
 	"main.c"
 	"application.c"
+	"scene.c"
 	"renderer/window.c"
 	"renderer/context.c"
 	"renderer/buffer.c" 
 	"renderer/shader.c"
 	"renderer/camera.c"
+ "objects/cube.c" "renderer/object.c")
+
+target_include_directories(solver PRIVATE
+	${CMAKE_CURRENT_LIST_DIR}
 )
 
+
 target_link_libraries(solver PRIVATE
 	glfw
 	glad
diff --git a/src/application.c b/src/application.c
index a24a6a4..cc77974 100644
--- a/src/application.c
+++ b/src/application.c
@@ -3,22 +3,19 @@
 #include <assert.h>
 #include <errno.h>
 
-#include <GLFW/glfw3.h>
-#include <cglm/affine.h>
-
 #include "renderer/context.h"
+#include "objects/cube.h"
 
 static void on_window_size_change(Application* app, int width, int height)
 {
-	set_camera_perspective(&app->camera, 90.0f, (float)width / (float)height);
+	scene_update_size(app->active_scene, width, height);
 }
 
 static void destroy_application(Application* app)
 {
 	assert(app);
 
-	destroy_vao(app->object);
-	destroy_window(app->window);
+	destroy_scene(*app->scenes);
 }
 
 int init_application(Application* app, const char* name)
@@ -35,91 +32,14 @@ int init_application(Application* app, const char* name)
 	app->window.user_data = app;
 	app->window.on_size_change = on_window_size_change;
 
-	// Create quad for testing
-	create_vao(&app->object);
+	app->scenes = (Scene*)malloc(1 * sizeof(Scene));
+	app->active_scene = app->scenes;	// First scene is active scene
 
-	float vertices[] = {
-		-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,	// front bottom left
-		-0.5f,  0.5f, -0.5f, 0.0f, 1.0f, 0.0f,	// front top left
-		 0.5f,  0.5f, -0.5f, 0.0f, 0.0f, 1.0f,	// front top right
-		 0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f,	// front bottom right
+	create_scene(app->scenes);
+	Cube* obj = (Cube*)malloc(sizeof(Cube));
+	create_cube(obj);
 
-		-0.5f, -0.5f,  0.5f, 1.0f, 1.0f, 1.0f,	// back bottom left
-		-0.5f,  0.5f,  0.5f, 1.0f, 0.0f, 0.0f,	// back top left
-		 0.5f,  0.5f,  0.5f, 0.0f, 1.0f, 0.0f,	// back top right
-		 0.5f, -0.5f,  0.5f, 0.0f, 0.0f, 1.0f,	// back bottom right
-	};
-	attach_vertex_buffer(&app->object, vertices, sizeof(vertices));
-
-	unsigned indices[] = {
-		0, 1, 2,	// front
-		0, 2, 3,
-
-		3, 2, 6,	// right
-		3, 6, 7,
-		
-		4, 5, 1,	// left
-		4, 1, 0,
-
-		7, 6, 5,	// back
-		7, 5, 4,
-
-		1, 5, 6,	// top
-		1, 6, 2,
-
-		4, 0, 3,	// bottom	
-		4, 3, 7
-	};
-	attach_element_buffer(&app->object, indices, sizeof(indices));
-
-	VertexAttribute layout[] = {
-		{ GL_FLOAT, 3, 3 * sizeof(float) },
-		{ GL_FLOAT, 3, 3 * sizeof(float) }
-	};
-	set_vertex_layout(&app->object, layout, sizeof(layout) / sizeof(VertexAttribute));
-
-	app->shader = create_shader(
-		"#version 460 core\n"
-		""
-		"layout (location = 0) in vec3 pos;"
-		"layout (location = 1) in vec3 col;"
-		""
-		"out vec3 i_col;"
-		""
-		"uniform mat4 model;"
-		"uniform mat4 view;"
-		"uniform mat4 projection;"
-		""
-		"void main() {"
-		"	i_col = col;"
-		"	gl_Position = projection * view * model * vec4(pos, 1.0);"
-		"}",
-
-		"#version 460 core\n"
-		""
-		"in  vec3 i_col;"
-		"out vec4 FragColor;"
-		""
-		"void main() {"
-		"	FragColor = vec4(i_col, 1.0);"
-		"}"
-	);
-	if(app->shader == 0)
-	{
-		destroy_application(app);
-		return 1;
-	}
-
-	if (create_camera(&app->camera) != 0)
-	{
-		destroy_application(app);
-		return 1;
-	}
-
-	glm_mat4_identity(app->model);
-
-	ctx_enable(GL_DEPTH_TEST);
-	ctx_front_face(GL_CW);
+	scene_add_object(app->active_scene, &obj->object);
 
 	return 0;
 }
@@ -130,17 +50,7 @@ int launch_application(Application* app)
 	{
 		glfwPollEvents();
 
-		// rotate cube
-		glm_rotate(app->model, 0.03f, (vec3) { 0.0f, 1.0f, 0.0f });
-
-		ctx_clear_screen(0.3f, 0.1f, 0.8f, 1.0f);
-
-		bind_shader(app->shader);
-		set_uniform_mat4(app->shader, "model", app->model);
-		set_uniform_mat4(app->shader, "view", app->camera.view);
-		set_uniform_mat4(app->shader, "projection", app->camera.projection);
-
-		ctx_draw_elements(&app->object);
+		render_scene(app->active_scene);
 
 		glfwSwapBuffers(app->window.window);
 	}
diff --git a/src/application.h b/src/application.h
index be37e8d..a71a7eb 100644
--- a/src/application.h
+++ b/src/application.h
@@ -2,18 +2,14 @@
 #define APPLICATION_H
 
 #include "renderer/window.h"
-#include "renderer/buffer.h"
-#include "renderer/shader.h"
-#include "renderer/camera.h"
+#include "scene.h"
 
 typedef struct Application 
 {
 	Window window;
 
-	VertexArrayObject object;
-	int shader;
-	Camera camera;
-	mat4 model;
+	Scene* scenes;
+	Scene* active_scene;
 } Application;
 
 int init_application(Application* app, const char* name);
diff --git a/src/objects/cube.c b/src/objects/cube.c
new file mode 100644
index 0000000..c9fb10e
--- /dev/null
+++ b/src/objects/cube.c
@@ -0,0 +1,149 @@
+#include "cube.h"
+
+#include <stdio.h>
+#include <glad/glad.h>
+
+static VertexArrayObject* vao = NULL;
+static Shader shader = 0;
+static size_t num_cubes = 0;
+
+static int init_cube_object(void)
+{
+	vao = (VertexArrayObject*) malloc(sizeof(VertexArrayObject));
+	if (vao == NULL) 
+	{
+		fprintf(stderr, "Failed to allocate memory for cube vao\n");
+		return 1;
+	}
+
+	create_vao(vao);
+
+	float cube_vertices[] = {
+		-1.0f, -1.0f, 1.0f,
+		-1.0f,  1.0f, 1.0f,
+		 1.0f,  1.0f, 1.0f,
+		 1.0f, -1.0f, 1.0f,
+
+		-1.0f, -1.0f, -1.0f,
+		-1.0f,  1.0f, -1.0f,
+		 1.0f,  1.0f, -1.0f,
+		 1.0f, -1.0f, -1.0f,
+	};
+	attach_vertex_buffer(vao, cube_vertices, sizeof(cube_vertices));
+
+	unsigned cube_indices[] = {
+		0, 1, 2, 2, 1, 3,
+		1, 5, 6, 1, 6, 2,
+		3, 2, 6, 3, 6, 7,
+		4, 5, 1, 4, 1, 0,
+		4, 0, 3, 4, 3, 7,
+		7, 6, 5, 7, 5, 4
+	};
+	attach_element_buffer(vao, cube_indices, sizeof(cube_indices));
+
+	VertexAttribute attributes[] = {
+		{ GL_FLOAT, 3, sizeof(float) }
+	};
+
+	set_vertex_layout(vao, attributes, sizeof(attributes) / sizeof(VertexAttribute));
+
+	shader = create_shader(
+		"#version 460 core\n"
+		""
+		"layout (location = 0) in vec3 pos;"
+		""
+		"uniform mat4 model;"
+		"uniform mat4 view;"
+		"uniform mat4 projection;"
+		""
+		"void main() {"
+		"	gl_Position = projection * view * model * vec4(pos, 1.0);"
+		"}",
+
+		"#version 460 core\n"
+		""
+		"uniform vec3 cube_color;"
+		"out vec4 FragColor;"
+		""
+		"void main() {"
+		"	FragColor = vec4(cube_color, 1.0);"
+		"}"
+	);
+	if (shader == 0) 
+	{ 
+		fprintf(stderr, "failed to create shader for cube\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static void on_shader_bind(Cube* cube)
+{
+	set_uniform_vec3(shader, "cube_color", cube->color);
+}
+
+static void on_update(Cube* cube)
+{
+	cube->object.rotation[1] += 0.05f;
+
+	for (int i = 0; i < 3; i++) 
+	{
+		cube->color[i] += cube->color_mod[i];
+
+		if (cube->color[i] > 1.0f) 
+		{
+			cube->color_mod[i] *= -1.0f;
+			cube->color[i] = 1.0f;
+		}
+		else if (cube->color[i] < 0.0f)
+		{
+			cube->color_mod[i] *= -1.0f;
+			cube->color[i] = 0.0f;
+		}
+	}
+}
+
+int create_cube(Cube* cube)
+{
+	if (vao == NULL || shader == 0)
+	{
+		if (init_cube_object() != 0)
+		{
+			return 1;
+		}
+	}
+
+	init_object(&cube->object);
+	glm_vec3_one(cube->color);
+
+	cube->color_mod[0] = 0.01f;
+	cube->color_mod[1] = 0.006f;
+	cube->color_mod[2] = 0.005f;
+
+	cube->object.vao = vao;
+	cube->object.shader = shader;
+
+	cube->object.child = cube;
+	cube->object.on_shader_use = on_shader_bind;
+	cube->object.on_update = on_update;
+	cube->object.on_destroy = destroy_cube;
+
+	num_cubes++;
+}
+
+void destroy_cube(Cube* cube)
+{
+	num_cubes--;
+
+	if (num_cubes == 0)
+	{
+		destroy_shader(shader);
+		shader = 0;
+
+		destroy_vao(*vao);
+		vao = NULL;
+	}
+}
+
+
diff --git a/src/objects/cube.h b/src/objects/cube.h
new file mode 100644
index 0000000..d913566
--- /dev/null
+++ b/src/objects/cube.h
@@ -0,0 +1,15 @@
+#ifndef OBJ_CUBE_H
+#define OBJ_CUBE_H
+
+#include "renderer/object.h"
+
+typedef struct Cube {
+	Object object;
+	vec3 color;
+	vec3 color_mod;
+} Cube;
+
+int create_cube(Cube* cube);
+void destroy_cube(Cube* cube);
+
+#endif // OBJ_CUBE_H
\ No newline at end of file
diff --git a/src/renderer/buffer.c b/src/renderer/buffer.c
index 7929cb4..c8c7268 100644
--- a/src/renderer/buffer.c
+++ b/src/renderer/buffer.c
@@ -50,7 +50,7 @@ void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size
 
 	size_t stride = 0;
 	for (size_t i = 0; i < count; i++) {
-		stride += attributes[i].size;
+		stride += attributes[i].size * attributes[i].count;
 	}
 
 	size_t offset = 0;
@@ -58,11 +58,16 @@ void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size
 		glVertexAttribPointer(i, attributes[i].count, attributes[i].type, GL_FALSE, stride, (const void*)(offset));
 		glEnableVertexAttribArray(i);
 
-		offset += attributes[i].size;
+		offset += attributes[i].size * attributes[i].count;
 	}
 }
 
-void bind_vao(VertexArrayObject vao)
+void bind_vao(VertexArrayObject* vao)
 {
-	glBindVertexArray(vao.vao);
+	glBindVertexArray(vao->vao);
+}
+
+void render_vao(VertexArrayObject* vao)
+{
+	glDrawArrays(GL_TRIANGLES, 0, vao->elements);
 }
diff --git a/src/renderer/buffer.h b/src/renderer/buffer.h
index f21d245..cd9186b 100644
--- a/src/renderer/buffer.h
+++ b/src/renderer/buffer.h
@@ -28,6 +28,7 @@ void attach_element_buffer(VertexArrayObject* vao, const unsigned* data, size_t
 
 void set_vertex_layout(VertexArrayObject* vao, VertexAttribute* attributes, size_t count);
 
-void bind_vao(VertexArrayObject vao);
+void bind_vao(VertexArrayObject* vao);
+void render_vao(VertexArrayObject* vao);
 
 #endif // BUFFER_H
\ No newline at end of file
diff --git a/src/renderer/camera.c b/src/renderer/camera.c
index 498f9da..c21da5c 100644
--- a/src/renderer/camera.c
+++ b/src/renderer/camera.c
@@ -10,7 +10,7 @@ int create_camera(Camera* camera)
 
 	glm_mat4_identity(camera->view);
 	glm_rotate(camera->view, glm_rad(35.0f), (vec3) { 1.0f, 0.0f, 0.0f });
-	glm_translate(camera->view, (vec3) { 0.0f, -1.0f, -2.0f });
+	glm_translate(camera->view, (vec3) { 0.0f, -1.5f, -3.0f });
 
 	glm_perspective(glm_rad(90.0f), 1.0f, 0.001f, 100.0f, camera->projection);
 
diff --git a/src/renderer/context.c b/src/renderer/context.c
index 3a31469..a9ebb4b 100644
--- a/src/renderer/context.c
+++ b/src/renderer/context.c
@@ -23,7 +23,7 @@ void ctx_clear_screen(float r, float g, float b, float a)
 
 void ctx_draw_elements(VertexArrayObject* vao)
 {
-	bind_vao(*vao);
+	bind_vao(vao);
 	glDrawElements(GL_TRIANGLES, vao->elements, GL_UNSIGNED_INT, (void*)0);
 }
 
diff --git a/src/renderer/object.c b/src/renderer/object.c
new file mode 100644
index 0000000..30f281e
--- /dev/null
+++ b/src/renderer/object.c
@@ -0,0 +1,44 @@
+#include "object.h"
+
+#include <cglm/affine.h>
+#include "context.h"
+
+void init_object(Object* obj)
+{
+	glm_mat4_identity(obj->transform);
+	glm_vec3_zero(obj->position);
+	glm_vec3_zero(obj->rotation);
+	glm_vec3_one(obj->scale);
+}
+
+void update_object(Object* obj)
+{
+	obj->on_update(obj->child);
+}
+
+void render_object(Object* obj, Camera* camera)
+{
+	bind_shader(obj->shader);
+
+	glm_mat4_identity(obj->transform);
+	float angle = glm_vec3_norm(obj->rotation);
+	vec3 normalized_rot;
+	glm_vec3_normalize_to(obj->rotation, normalized_rot);
+
+	glm_scale(obj->transform, obj->scale);
+	glm_rotate(obj->transform, angle, normalized_rot);
+	glm_scale(obj->transform, obj->scale);
+
+	set_uniform_mat4(obj->shader, "model", obj->transform);
+	set_uniform_mat4(obj->shader, "view", camera->view);
+	set_uniform_mat4(obj->shader, "projection", camera->projection);
+
+	obj->on_shader_use(obj->child);
+
+	ctx_draw_elements(obj->vao);
+}
+
+void destroy_object(Object obj)
+{
+	obj.on_destroy(obj.child);
+}
diff --git a/src/renderer/object.h b/src/renderer/object.h
new file mode 100644
index 0000000..88783f9
--- /dev/null
+++ b/src/renderer/object.h
@@ -0,0 +1,32 @@
+#ifndef OBJECT_H
+#define OBJECT_H
+
+#include <cglm/mat4.h>
+
+#include "shader.h"
+#include "buffer.h"
+#include "camera.h"
+
+typedef struct Object
+{
+	VertexArrayObject* vao;
+	Shader shader;
+
+	mat4 transform;
+	vec3 position;
+	vec3 rotation;
+	vec3 scale;
+
+	void* child;
+	void(*on_shader_use)(void*);
+	void(*on_update)(void*);
+	void(*on_destroy)(void*);
+} Object;
+
+void init_object(Object* obj);
+void destroy_object(Object obj);
+
+void update_object(Object* obj);
+void render_object(Object* obj, Camera* camera);
+
+#endif // OBJECT_H
\ No newline at end of file
diff --git a/src/renderer/shader.c b/src/renderer/shader.c
index af17022..bd5c720 100644
--- a/src/renderer/shader.c
+++ b/src/renderer/shader.c
@@ -32,7 +32,7 @@ static int set_and_compile_shader(GLuint program, GLuint shader, const char* cod
 	return 0;
 }
 
-int create_shader(const char* vertex_shader_code, const char* fragment_shader_code)
+Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code)
 {
 	assert(vertex_shader_code && fragment_shader_code);
 
@@ -83,18 +83,24 @@ vertex_failed:
 	return shader;
 }
 
-void destroy_shader(int shader)
+void destroy_shader(Shader shader)
 {
 	glDeleteProgram(shader);
 }
 
-void bind_shader(int shader)
+void bind_shader(Shader shader)
 {
 	glUseProgram(shader);
 }
 
-void set_uniform_mat4(int shader, const char* name, mat4 mat)
+void set_uniform_mat4(Shader shader, const char* name, mat4 mat)
 {
 	int location = glGetUniformLocation(shader, name);
 	glUniformMatrix4fv(location, 1, GL_FALSE, (float*)mat);
-}
\ No newline at end of file
+}
+
+void set_uniform_vec3(Shader shader, const char* name, vec3 vec)
+{
+	int location = glGetUniformLocation(shader, name);
+	glUniform3fv(location, 1, vec);
+}
diff --git a/src/renderer/shader.h b/src/renderer/shader.h
index a77078e..30693cb 100644
--- a/src/renderer/shader.h
+++ b/src/renderer/shader.h
@@ -3,10 +3,14 @@
 
 #include <cglm/mat4.h>
 
-int create_shader(const char* vertex_shader_code, const char* fragment_shader_code);
-void destroy_shader(int shader);
+typedef int Shader;
 
-void bind_shader(int shader);
-void set_uniform_mat4(int shader, const char* name, mat4 mat);
+Shader create_shader(const char* vertex_shader_code, const char* fragment_shader_code);
+void destroy_shader(Shader shader);
+
+void bind_shader(Shader shader);
+
+void set_uniform_mat4(Shader shader, const char* name, mat4 mat);
+void set_uniform_vec3(Shader shader, const char* name, vec3 vec);
 
 #endif // SHADER_H
\ No newline at end of file
diff --git a/src/renderer/window.c b/src/renderer/window.c
index 7ce3301..d5f8fbf 100644
--- a/src/renderer/window.c
+++ b/src/renderer/window.c
@@ -33,6 +33,8 @@ int create_managed_window(Window* window, const char* title, int width, int heig
 
 	glfwMakeContextCurrent(window->window);
 	ctx_init();
+	ctx_enable(GL_DEPTH_TEST);
+	ctx_front_face(GL_CW);
 
 	glfwSetFramebufferSizeCallback(window->window, default_framebuffer_size_callback);
 	
diff --git a/src/scene.c b/src/scene.c
new file mode 100644
index 0000000..b2f7f8f
--- /dev/null
+++ b/src/scene.c
@@ -0,0 +1,48 @@
+#include "scene.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include <glad/glad.h>
+
+#include "objects/cube.h"
+
+int create_scene(Scene* scene)
+{
+	assert(scene);
+
+	if (create_camera(&scene->camera) != 0)
+	{
+		fprintf(stderr, "Failed to set up camera for scene\n");
+		return 1;
+	}
+
+	scene->objects = (Object*)malloc(sizeof(Object));
+}
+
+void destroy_scene(Scene scene)
+{
+	destroy_object(*(scene.objects));
+}
+
+void scene_add_object(Scene* scene, Object* object)
+{
+	assert(scene);
+
+	scene->objects = object;
+}
+
+void scene_update_size(Scene* scene, int width, int height)
+{
+	assert(scene);
+	set_camera_perspective(&scene->camera, 90.0f, (float)width / (float)height);
+}
+
+void render_scene(Scene* scene)
+{
+	assert(scene);
+	ctx_clear_screen(0.0f, 0.0f, 0.0f, 1.0f);
+
+	update_object(scene->objects);
+	render_object(scene->objects, &scene->camera);
+}
diff --git a/src/scene.h b/src/scene.h
new file mode 100644
index 0000000..64acafc
--- /dev/null
+++ b/src/scene.h
@@ -0,0 +1,21 @@
+#ifndef SCENE_H
+#define SCENE_H
+
+#include "renderer/camera.h"
+#include "renderer/object.h"
+
+typedef struct Scene
+{
+	Camera camera;
+	Object* objects;
+} Scene;
+
+int create_scene(Scene* scene);
+void destroy_scene(Scene scene);
+
+void scene_add_object(Scene* scene, Object* object);
+void scene_update_size(Scene* scene, int width, int height);
+
+void render_scene(Scene* scene);
+
+#endif
\ No newline at end of file