diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9bd00ee2..af4c4e6b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@ set(SETTING_GAME_POKER 1)
 set(SETTING_GAME_DAWN 2)
 set(SETTING_GAME_SANDBOX 3)
 
-set(SETTING_GAME SETTING_GAME_POKER)
+set(SETTING_GAME SETTING_GAME_SANDBOX)
 set(SETTING_GAME_NAME "DawnGame")
 
 ################################## Targets #####################################
diff --git a/assets/shaders/textured.frag b/assets/shaders/textured.frag
index 19642c82..78bcd501 100644
--- a/assets/shaders/textured.frag
+++ b/assets/shaders/textured.frag
@@ -1,25 +1,11 @@
-#version 300 es
+#version 330 core
 
-#ifdef GL_ES
-  in mediump vec2 TexCoord;
-  uniform mediump sampler2D u_Text;
-  out mediump vec4 FragColor;
-  
-  void main() {
-    mediump vec4 color = texture(u_Text, TexCoord);
-    // if(color.a == 0.0) discard;
-    FragColor = color;
-  }
-#else
-  #version 330 core
+in vec2 TexCoord;
+uniform sampler2D u_Text;
+uniform vec4 u_Colr;
+out vec4 FragColor;
 
-  in vec2 TexCoord;
-  uniform sampler2D u_Text;
-  out vec4 FragColor;
-
-  void main() {
-    vec4 color = texture(u_Text, TexCoord);
-    // if(color.a == 0.0) discard;
-    FragColor = color;
-  }
-#endif
\ No newline at end of file
+void main() {
+  vec4 color = texture(u_Text, TexCoord);
+  FragColor = color * u_Colr;
+}
\ No newline at end of file
diff --git a/include/dawn/display/shader.h b/include/dawn/display/shader.h
index 85671495..53249141 100644
--- a/include/dawn/display/shader.h
+++ b/include/dawn/display/shader.h
@@ -12,6 +12,7 @@
 #define SHADER_UNI_PROJ "u_Proj"
 #define SHADER_UNI_TEXT "u_Text"
 #define SHADER_UNI_MODL "u_Modl"
+#define SHADER_UNI_COLR "u_Colr"
 
 /** Representation of a shader uniform */
 typedef GLuint shaderuniform_t;
@@ -41,4 +42,7 @@ typedef struct {
 
   /** Uniform for the current model world position */
   shaderuniform_t uniModl;
+
+  /** Uniform for the color multiplier */
+  shaderuniform_t uniColr;
 } shader_t;
\ No newline at end of file
diff --git a/include/dawn/display/texture.h b/include/dawn/display/texture.h
index 95b874c6..25acf444 100644
--- a/include/dawn/display/texture.h
+++ b/include/dawn/display/texture.h
@@ -25,3 +25,10 @@ typedef struct {
   /** RGBA Color values */
   uint8_t r, g, b, a;
 } pixel_t;
+
+#define PIXEL_COLOR_WHITE ((pixel_t){ .r = 255, .g = 255, .b = 255, .a = 255 })
+#define PIXEL_COLOR_RED ((pixel_t){ .r = 255, .g = 0, .b = 0, .a = 255 })
+#define PIXEL_COLOR_GREEN ((pixel_t){ .r = 0, .g = 255, .b = 0, .a = 255 })
+#define PIXEL_COLOR_BLUE ((pixel_t){ .r = 0, .g = 0, .b = 255, .a = 255 })
+#define PIXEL_COLOR_BLACK ((pixel_t){ .r = 0, .g = 0, .b = 0, .a = 255 })
+#define PIXEL_COLOR_TRANSPARENT ((pixel_t){ .r = 0, .g = 0, .b = 0, .a = 0 })
\ No newline at end of file
diff --git a/include/dawn/game/poker/ui/pokerplayerui.h b/include/dawn/game/poker/ui/pokerplayerui.h
index e68c90ac..37e90d91 100644
--- a/include/dawn/game/poker/ui/pokerplayerui.h
+++ b/include/dawn/game/poker/ui/pokerplayerui.h
@@ -17,6 +17,7 @@
 #define POKER_PLAYER_UI_IMAGE_DIST 0.8f
 #define POKER_PLAYER_UI_IMAGE_Y 0.1f
 #define POKER_PLAYER_UI_PADDING 8
+#define POKER_PLAYER_UI_CHIPS_ANIMATION_SPEED 0.5f
 
 typedef struct {
   label_t label;
diff --git a/include/dawn/game/sandbox/sandboxscene.h b/include/dawn/game/sandbox/sandboxscene.h
index e4f80ac1..c81fff80 100644
--- a/include/dawn/game/sandbox/sandboxscene.h
+++ b/include/dawn/game/sandbox/sandboxscene.h
@@ -12,13 +12,20 @@
 #include "../../display/font.h"
 #include "../../display/primitive.h"
 #include "../../display/renderlist.h"
+#include "../../display/texture.h"
+
+#define GRID_BRUH_COUNT 1
+
+typedef struct {
+  float x, y, width, height;
+} gridbruh_t;
 
 typedef struct {
   camera_t camera;
-  renderlist_t list;
 
-  shader_t shader;
+  primitive_t primitive;
   texture_t texture;
-  
-  primitive_t cube;
+  shader_t shader;
+
+  gridbruh_t items[GRID_BRUH_COUNT];
 } sandboxscene_t;
\ No newline at end of file
diff --git a/src/display/shader.c b/src/display/shader.c
index 0e3a98ba..24b65779 100644
--- a/src/display/shader.c
+++ b/src/display/shader.c
@@ -76,12 +76,14 @@ void shaderInit(shader_t *shader,
   shader->uniView = glGetUniformLocation(shader->shaderProgram,SHADER_UNI_VIEW);
   shader->uniText = glGetUniformLocation(shader->shaderProgram,SHADER_UNI_TEXT);
   shader->uniModl = glGetUniformLocation(shader->shaderProgram,SHADER_UNI_MODL);
+  shader->uniColr = glGetUniformLocation(shader->shaderProgram,SHADER_UNI_COLR);
 
   // Bind the shader
   shaderUse(shader);
 
   // Reset position
   shaderUsePosition(shader, 0, 0, 0, 0, 0, 0);
+  shaderUseColor(shader, PIXEL_COLOR_WHITE);
 }
 
 void shaderDispose(shader_t *shader) {
@@ -144,4 +146,13 @@ void shaderUsePositionAndScale(shader_t *shader,
   matrixScale(&matrix, scaleX, scaleY, scaleZ);
 
   shaderUseMatrix(shader, shader->uniModl, &matrix);
+}
+
+void shaderUseColor(shader_t *shader, pixel_t color) {
+  glUniform4f(shader->uniColr,
+    (float)color.r / 255.0f,
+    (float)color.g / 255.0f,
+    (float)color.b / 255.0f,
+    (float)color.a / 255.0f 
+  );
 }
\ No newline at end of file
diff --git a/src/display/shader.h b/src/display/shader.h
index b35e4cac..a4b08bf5 100644
--- a/src/display/shader.h
+++ b/src/display/shader.h
@@ -91,4 +91,7 @@ void shaderUsePositionAndScale(shader_t *shader,
   float x, float y, float z,
   float pitch, float yaw, float roll,
   float scaleX, float scaleY, float scaleZ
-);
\ No newline at end of file
+);
+
+
+void shaderUseColor(shader_t *shader, pixel_t color);
\ No newline at end of file
diff --git a/src/game/poker/ui/pokerplayerui.c b/src/game/poker/ui/pokerplayerui.c
index 974b97ea..901ab64d 100644
--- a/src/game/poker/ui/pokerplayerui.c
+++ b/src/game/poker/ui/pokerplayerui.c
@@ -9,11 +9,9 @@
 
 void pokerPlayerUiInit(pokerplayerui_t *ui) {
   labelInit(&ui->label);
-  
   frameBufferInit(&ui->frame,
     POKER_PLAYER_UI_IMAGE_RESOLUTION, POKER_PLAYER_UI_IMAGE_RESOLUTION
   );
-
   quadInit(&ui->quad, 0,
     0, 0, 0, 1,
     POKER_PLAYER_UI_IMAGE_SIZE, POKER_PLAYER_UI_IMAGE_SIZE, 1, 0
@@ -24,11 +22,13 @@ void pokerPlayerUiUpdate(
   pokerplayerui_t *ui, pokergame_t *game, shader_t *shader, int32_t playerIndex,
   engine_t *engine
 ) {
-  
   camera_t camera;
   uint8_t seat;
+  pokerplayer_t *player;
   float x, y, z;
 
+  player = game->poker.players + playerIndex;
+
   // Bind the frame buffer
   frameBufferUse(&ui->frame, true);
 
diff --git a/src/game/poker/ui/pokerui.c b/src/game/poker/ui/pokerui.c
index 2435e1a6..ae79c108 100644
--- a/src/game/poker/ui/pokerui.c
+++ b/src/game/poker/ui/pokerui.c
@@ -8,42 +8,53 @@
 #include "pokerui.h"
 
 void pokerUiInit(pokergame_t *pokerGame) {
-  uint8_t i;
+  uint8_t i, j;
 
+  j = 0;
   for(i = 0; i < POKER_PLAYER_COUNT; i++) {
-    pokerPlayerUiInit(pokerGame->ui.player + i);
+    if(i == POKER_PLAYER_HUMAN_INDEX) continue;
+    pokerPlayerUiInit(pokerGame->ui.player + j);
+    j++;
   }
 }
 
 void pokerUiUpdate(pokergame_t *pokerGame, engine_t *engine) {
-  uint8_t i;
+  uint8_t i, j;
   pokerplayerui_t *ui;
 
+  j = 0;
   for(i = 0; i < POKER_PLAYER_COUNT; i++) {
-    ui = pokerGame->ui.player + i;
-
+    if(i == POKER_PLAYER_HUMAN_INDEX) continue;
+    ui = pokerGame->ui.player + j;
     pokerPlayerUiUpdate(ui, pokerGame, &pokerGame->assets.shader, i, engine);
+    j++;
   }
 }
 
 void pokerUiRender(pokergame_t *pokerGame, engine_t *engine) {
-  uint8_t i;
+  uint8_t i, j;
   pokerplayerui_t *ui;
 
+  j = 0;
   for(i = 0; i < POKER_PLAYER_COUNT; i++) {
-    ui = pokerGame->ui.player + i;
+    if(i == POKER_PLAYER_HUMAN_INDEX) continue;
+    ui = pokerGame->ui.player + j;
 
     pokerPlayerUiRender(ui, pokerGame,
       &pokerGame->assets.shader, &pokerGame->assets.font, i,
-      engine->render.width, i * 75.0f
+      engine->render.width, j * 75.0f
     );
+    j++;
   }
 }
 
 void pokerUiDispose(pokergame_t *pokerGame) {
-  uint8_t i;
+  uint8_t i, j;
 
+  j = 0;
   for(i = 0; i < POKER_PLAYER_COUNT; i++) {
-    pokerPlayerUiDispose(pokerGame->ui.player + i);
+    if(i == POKER_PLAYER_HUMAN_INDEX) continue;
+    pokerPlayerUiDispose(pokerGame->ui.player + j);
+    j++;
   }
 }
\ No newline at end of file
diff --git a/src/game/sandbox/sandboxscene.c b/src/game/sandbox/sandboxscene.c
index fe7a5071..61056ef0 100644
--- a/src/game/sandbox/sandboxscene.c
+++ b/src/game/sandbox/sandboxscene.c
@@ -7,50 +7,75 @@
 
 #include "sandboxscene.h"
 
-void renderTest(renderlist_t *list, renderpass_t *pass, engine_t *engine, int32_t i) {
-  sandboxscene_t *scene;
-  scene = (sandboxscene_t *)list->user;
+grid_t grid;
 
-  shaderUsePosition(pass->shader, 0, 0, 0, engine->time.current, engine->time.current, 0);
-  shaderUseTexture(pass->shader, &scene->texture);
-  primitiveDraw(&scene->cube, 0, -1);
+void gridTest(
+  void *user, int32_t i,
+  float screenWidth, float screenHeight,
+  float x, float y,
+  float width, float height
+) {
+  sandboxscene_t *game = (sandboxscene_t *)user;
+  game->items[i].x = x;
+  game->items[i].y = y;
+  game->items[i].width = width;
+  game->items[i].height = height;
 }
 
 bool sandboxSceneInit(sandboxscene_t *game) {
-  int32_t passIndex;
-  renderpass_t *pass;
+  gridInit(&grid);
+  grid.user = (void *)game;
+
+  gridAddBreakpoint(&grid, 800, 2, 2, 8.0f, 8.0f);
+  gridAddBreakpoint(&grid, -1, 6, 6, 16.0f, 16.0f);
+
+  gridchild_t *child = gridAddChild(&grid);
+  child->onResize = &gridTest;
 
-  // Load assets
   assetTextureLoad(&game->texture, "test_texture.png");
-  assetShaderLoad(&game->shader, "shaders/textured.vert", "shaders/textured.frag");
-  cubeInit(&game->cube, 1.0f, 1.0f, 1.0f);
-
-  // Initialize list
-  renderListInit(&game->list, 1, 400, 400);
-  game->list.user = game;
-
-  // Set up the pass
-  passIndex = renderPassAdd(&game->list);
-  pass = renderListGetPass(&game->list, passIndex);
-  pass->shader = &game->shader;
+  assetShaderLoad(&game->shader, 
+    "shaders/textured.vert", "shaders/textured.frag"
+  );
+  quadInit(&game->primitive, 0,
+    0,0,0,0,
+    1,1,1,1
+  );
 
   return true;
 }
 
 void sandboxSceneUpdate(sandboxscene_t *game, engine_t *engine) {
-  dynarray_t items;
-  renderitem_t *item;
-  dynArrayInit(&items, sizeof(renderitem_t), 1);
-  item = (renderitem_t *)dynArrayGet(&items, dynArrayAdd(&items));
-  item->onRender=  &renderTest;
+  cameraLookAt(&game->camera,
+    0, 0, 10,
+    0, 0, 0
+  );
 
-  cameraLookAt(&game->camera, 3,3,3, 0,0,0);
-  cameraPerspective(&game->camera, 75, 16.0f/9.0f, 0.3f, 100.0f);
+  cameraOrtho(&game->camera,
+    0, engine->render.width,
+    engine->render.height, 0,
+    0.01f, 1000.0f
+  );
+
+  shaderUse(&game->shader);
+  shaderUseCamera(&game->shader, &game->camera);
+  shaderUseTexture(&game->shader, &game->texture);
+
+  gridSetSize(&grid,
+    engine->render.width, engine->render.height,
+    engine->render.width, engine->render.height,
+    0, 0
+  );
   
-  renderListRenderPass(&game->list, engine, &game->camera, 0, &items);
-  renderListRender(&game->list, engine, &game->shader);
 
-  dynArrayDispose(&items);
+  for(uint8_t i = 0; i < GRID_BRUH_COUNT; i++) {
+    gridbruh_t *b = game->items + i;
+    shaderUsePositionAndScale(&game->shader, 
+      b->x, b->y, 0,
+      0, 0, 0,
+      b->width, b->height, 1
+    );
+    primitiveDraw(&game->primitive, 0, -1);
+  }
 }
 
 void sandboxSceneDispose(sandboxscene_t *game) {
diff --git a/src/game/sandbox/sandboxscene.h b/src/game/sandbox/sandboxscene.h
index 29c3dde5..1991f8ee 100644
--- a/src/game/sandbox/sandboxscene.h
+++ b/src/game/sandbox/sandboxscene.h
@@ -14,7 +14,9 @@
 #include "../../display/primitives/quad.h"
 #include "../../display/primitives/cube.h"
 #include "../../display/renderlist.h"
+#include "../../display/texture.h"
 #include "../../file/asset.h"
+#include "../../ui/grid.h"
 
 /**
  * Initialize the sandbox scene test game.
diff --git a/src/ui/grid.c b/src/ui/grid.c
new file mode 100644
index 00000000..12dc5332
--- /dev/null
+++ b/src/ui/grid.c
@@ -0,0 +1,118 @@
+/**
+ * Copyright (c) 2021 Dominic Masters
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#include "grid.h"
+
+void gridInit(grid_t *grid) {
+  grid->breakpointCount = 0x00;
+  grid->childCount = 0x00;
+  grid->width = 0;
+  grid->height = 0;
+  grid->x = 0;
+  grid->y = 0;
+}
+
+uint8_t gridAddBreakpoint(
+  grid_t *grid, float width,
+  uint8_t rows, uint8_t columns,
+  float gutterX, float gutterY
+) {
+  uint8_t i;
+  i = grid->breakpointCount;
+  grid->grids[i].rows = rows;
+  grid->grids[i].columns = columns;
+  grid->grids[i].gutterX = gutterX;
+  grid->grids[i].gutterY = gutterY;
+  grid->breakpoints[i].width = width;
+  grid->breakpointCount++;
+  return i;
+}
+
+gridchild_t * gridAddChild(grid_t *grid) {
+  gridchild_t *child = grid->children + grid->childCount;
+  child->defCount = 1;
+  child->defs[0].columns = 1;
+  child->defs[0].rows = 1;
+  child->defs[0].x = 0;
+  child->defs[0].y = 0;
+  grid->childCount++;
+  return child;
+}
+
+void gridSetSize(grid_t *grid,
+  float screenWidth, float screenHeight,
+  float width, float height,
+  float x, float y
+) {
+  uint8_t i, breakpoint;
+  gridchild_t *item;
+  gridchilddef_t *itemdef;
+  griddef_t griddef;
+  float sizeCol, sizeRow, gx, gy, gw, gh;
+
+  // Need to resize?
+  if((
+    grid->width == width && grid->height == height &&
+    grid->x == x && grid->y == y
+  )) {
+    return;
+  }
+
+  // Update properties
+  grid->width = width;
+  grid->height = height;
+  grid->x = x;
+  grid->y = y;
+
+  // Determine breakpoint
+  breakpoint = 0xFF;
+  for(i = 0; i < grid->breakpointCount; i++) {
+    if(grid->breakpoints[i].width < screenWidth) continue;
+    breakpoint = i;
+  }
+  if(breakpoint == 0xFF) breakpoint = grid->breakpointCount - 1;
+  griddef = grid->grids[breakpoint];
+
+  // Determine the size of a single column
+  sizeCol = (width - (
+    griddef.gutterX * (griddef.columns - 1)
+  )) / griddef.columns;
+
+  sizeRow = (height - (
+    griddef.gutterY * (griddef.rows - 1)
+  )) / griddef.rows;
+
+  // Resize children
+  for(i = 0; i < grid->childCount; i++) {
+    // Get the item and the definition.
+    item = grid->children + i;
+    itemdef = item->defs + (
+      breakpoint >= item->defCount ? item->defCount-1 : breakpoint
+    );
+
+    // Get the local X/Y
+    gx = (sizeCol * itemdef->x) + (griddef.gutterX * itemdef->x);
+    gy = (sizeRow * itemdef->y) + (griddef.gutterY * itemdef->y);
+
+    // Get the width/height
+    gw = (
+      (itemdef->columns * sizeCol) + 
+      (mathMax(itemdef->columns - 1, 0) * griddef.gutterX)
+    );
+    gh = (
+      (itemdef->rows * sizeRow) + 
+      (mathMax(itemdef->rows - 1, 0) * griddef.gutterY)
+    );
+
+    item->onResize(
+      grid->user, i,
+      screenWidth, screenHeight,
+      x + gx,y + gy,
+      gw, gh
+    );
+  }
+}
\ No newline at end of file
diff --git a/src/ui/grid.h b/src/ui/grid.h
new file mode 100644
index 00000000..2faa6c72
--- /dev/null
+++ b/src/ui/grid.h
@@ -0,0 +1,77 @@
+/**
+ * Copyright (c) 2021 Dominic Masters
+ * 
+ * This software is released under the MIT License.
+ * https://opensource.org/licenses/MIT
+ */
+
+#pragma once
+#include <dawn/dawn.h>
+
+#define BREAKPOINT_COUNT 4
+
+#define GRID_CHILD_COUNT 32
+
+typedef struct {
+  float width;
+} breakpoint_t;
+
+typedef struct {
+  uint8_t rows;
+  uint8_t columns;
+  float gutterX;
+  float gutterY;
+} griddef_t;
+
+typedef void gridchildresizecallback_t(
+  void *user, int32_t i,
+  float screenWidth, float screenHeight,
+  float x, float y,
+  float width, float height
+);
+
+typedef struct {
+  uint8_t columns;
+  uint8_t rows;
+  uint8_t x;
+  uint8_t y;
+} gridchilddef_t;
+
+typedef struct {
+  gridchilddef_t defs[BREAKPOINT_COUNT];
+  uint8_t defCount;
+  gridchildresizecallback_t *onResize;
+} gridchild_t;
+
+typedef struct {
+  griddef_t grids[BREAKPOINT_COUNT];
+  breakpoint_t breakpoints[BREAKPOINT_COUNT];
+  gridchild_t children[GRID_CHILD_COUNT];
+  uint8_t childCount;
+
+  float width;
+  float height;
+  float x;
+  float y;
+  
+  uint8_t breakpointCount;
+  void *user;
+} grid_t;
+
+
+void gridInit(grid_t *grid);
+
+uint8_t gridAddBreakpoint(
+  grid_t *grid, float width,
+  uint8_t rows, uint8_t columns,
+  float gutterX, float gutterY
+);
+
+gridchild_t * gridAddChild(grid_t *grid);
+
+
+void gridSetSize(grid_t *grid,
+  float screenWidth, float screenHeight,
+  float width, float height,
+  float x, float y
+);
\ No newline at end of file