diff --git a/crates/lyra-game/src/render/graph/passes/sprite.rs b/crates/lyra-game/src/render/graph/passes/sprite.rs
index 96f8899..60da3ae 100644
--- a/crates/lyra-game/src/render/graph/passes/sprite.rs
+++ b/crates/lyra-game/src/render/graph/passes/sprite.rs
@@ -415,19 +415,27 @@ impl Node for SpritePass {
                     }
                 }
 
+                // Get the transform accounting for the sprite pivot
                 let pivot = atlas_sprite
+                    .as_ref()
                     .map(|ats| ats.0.pivot)
                     // unwrap is safe since its either AtlasSprite or Sprite.
-                    .unwrap_or_else(|| sprite.unwrap().pivot)
+                    .unwrap_or_else(|| sprite.as_ref().unwrap().pivot)
                     .as_vec();
-
                 let pivot_pos = dim.as_vec2() * (pivot - Vec2::splat(0.5));
                 let transform =
                     *transform + lyra_math::Transform::from_translation(pivot_pos.extend(0.0));
 
+                let tint = sprite
+                    .map(|s| s.color)
+                    .or_else(|| atlas_sprite.map(|(ats, _)| ats.color))
+                    .unwrap_or(Vec3::ONE);
+
                 let inst = SpriteInstance {
                     atlas_frame: rect.unwrap_or(URect::ZERO),
                     transform: transform.calculate_mat4(),
+                    color_tint: tint,
+                    _padding: 0,
                 };
                 sprite_instances.push(inst);
                 let inst_id = sprite_instances.len() as u64 - 1;
@@ -555,4 +563,6 @@ impl Node for SpritePass {
 struct SpriteInstance {
     atlas_frame: URect,
     transform: glam::Mat4,
+    color_tint: glam::Vec3,
+    _padding: u32,
 }
diff --git a/crates/lyra-game/src/render/shaders/2d/sprite_main.wgsl b/crates/lyra-game/src/render/shaders/2d/sprite_main.wgsl
index 8654a14..1e8a57f 100644
--- a/crates/lyra-game/src/render/shaders/2d/sprite_main.wgsl
+++ b/crates/lyra-game/src/render/shaders/2d/sprite_main.wgsl
@@ -26,6 +26,7 @@ struct URect {
 struct SpriteInstance {
     atlas_frame: URect,
     transform: mat4x4<f32>,
+    color: vec3<f32>,
 }
 
 struct CameraUniform {
@@ -82,10 +83,13 @@ fn fs_main(in: VertexOutput) -> @location(0) vec4<f32> {
         region_coords /= dim;
     }
 
-    let object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, region_coords);
+    var object_color: vec4<f32> = textureSample(t_diffuse, s_diffuse, region_coords);
     if (object_color.a < ALPHA_CUTOFF) {
         discard;
     }
 
+    // apply color tint
+    object_color = vec4<f32>(object_color.rgb * sprite.color.rgb, object_color.a);
+
     return object_color;
-}
\ No newline at end of file
+}
diff --git a/crates/lyra-game/src/sprite/animation_sheet.rs b/crates/lyra-game/src/sprite/animation_sheet.rs
index 6a1ad54..cc86f7c 100644
--- a/crates/lyra-game/src/sprite/animation_sheet.rs
+++ b/crates/lyra-game/src/sprite/animation_sheet.rs
@@ -38,7 +38,13 @@ impl SpriteAnimation {
     /// * `frame_time` - The time per frame of the animation.
     /// * `atlas` - The texture atlas that this animation is from, used to acquire `self.frames`.
     /// * `sprites` are the rect indexes in the atlas for this animation.
-    pub fn from_atlas<I>(name: &str, frame_time: f32, atlas: &TextureAtlas, auto_loop: bool, sprites: I) -> Self
+    pub fn from_atlas<I>(
+        name: &str,
+        frame_time: f32,
+        atlas: &TextureAtlas,
+        auto_loop: bool,
+        sprites: I,
+    ) -> Self
     where
         I: Iterator<Item = u32>,
     {
@@ -96,14 +102,18 @@ impl AtlasAnimations {
     pub fn from_animations(
         atlas: ResHandle<TextureAtlas>,
         animations: Vec<SpriteAnimation>,
-        sprite_pivot: Pivot
+        sprite_pivot: Pivot,
     ) -> Self {
         let animations = animations
             .into_iter()
             .map(|a| (a.name.clone(), a))
             .collect::<HashMap<_, _>>();
 
-        Self { atlas, animations, sprite_pivot }
+        Self {
+            atlas,
+            animations,
+            sprite_pivot,
+        }
     }
 
     /// Helper for creating [`AtlasAnimations`].
@@ -140,7 +150,11 @@ impl AtlasAnimations {
                 .collect::<HashMap<_, _>>()
         };
 
-        Self { atlas, animations, sprite_pivot }
+        Self {
+            atlas,
+            animations,
+            sprite_pivot,
+        }
     }
 
     /// Get the [`ActiveAtlasAnimation`] for an animation with `name`.
@@ -282,6 +296,7 @@ fn system_animation_entity_impl(
                     atlas: animations.atlas.clone(),
                     sprite: rect,
                     pivot: animations.sprite_pivot,
+                    ..Default::default()
                 };
 
                 commands.insert(en, sprite);
@@ -313,6 +328,7 @@ fn system_animation_entity_impl(
                     atlas: animations.atlas.clone(),
                     sprite: rect,
                     pivot: animations.sprite_pivot,
+                    ..Default::default()
                 };
 
                 let sprite = sprite.as_mut().unwrap();
diff --git a/crates/lyra-game/src/sprite/texture_atlas.rs b/crates/lyra-game/src/sprite/texture_atlas.rs
index ca3b9cf..d3886fa 100644
--- a/crates/lyra-game/src/sprite/texture_atlas.rs
+++ b/crates/lyra-game/src/sprite/texture_atlas.rs
@@ -1,4 +1,4 @@
-use glam::UVec2;
+use glam::{UVec2, Vec3};
 use lyra_ecs::Component;
 use lyra_math::URect;
 use lyra_reflect::Reflect;
@@ -15,7 +15,7 @@ pub struct TextureAtlas {
 
 impl TextureAtlas {
     /// Create a texture atlas with rectangles of a grid.
-    /// 
+    ///
     /// Parameters:
     /// * `texture` - The asset handle of the texture to get the sprites from.
     /// * `grid_size` - The number of the cells in the grid (i.e., 9x7 grid).
@@ -40,7 +40,7 @@ impl TextureAtlas {
             if y > 0 {
                 p.y = padding.y;
             }
-            
+
             for x in 0..grid_size.x {
                 if x > 0 {
                     p.x = padding.x;
@@ -49,12 +49,7 @@ impl TextureAtlas {
                 let start = (cell_size + padding) * UVec2::new(x, y) + offset;
                 let end = start + cell_size;
 
-                let r = URect::new(
-                    start.x,
-                    start.y,
-                    end.x,
-                    end.y,
-                );
+                let r = URect::new(start.x, start.y, end.x, end.y);
                 frames.push(r);
             }
         }
@@ -83,6 +78,18 @@ pub struct AtlasSprite {
     pub atlas: ResHandle<TextureAtlas>,
     pub sprite: URect,
     pub pivot: Pivot,
+    pub color: Vec3,
+}
+
+impl Default for AtlasSprite {
+    fn default() -> Self {
+        Self {
+            atlas: Default::default(),
+            sprite: Default::default(),
+            pivot: Default::default(),
+            color: Vec3::ONE,
+        }
+    }
 }
 
 impl AtlasSprite {
@@ -102,6 +109,7 @@ impl AtlasSprite {
             atlas: atlas.clone(),
             sprite: rect,
             pivot,
+            color: Vec3::ONE,
         }
     }
 }
diff --git a/crates/lyra-game/src/sprite/tilemap.rs b/crates/lyra-game/src/sprite/tilemap.rs
index 44c5b03..3275c07 100644
--- a/crates/lyra-game/src/sprite/tilemap.rs
+++ b/crates/lyra-game/src/sprite/tilemap.rs
@@ -152,6 +152,7 @@ pub fn system_tilemap_update(
                     atlas: atlas_handle.clone(),
                     sprite: *frame,
                     pivot: super::Pivot::TopLeft,
+                    ..Default::default()
                 };
 
                 commands.insert(en, sprite);
@@ -171,6 +172,7 @@ pub fn system_tilemap_update(
                             atlas: atlas_handle.clone(),
                             sprite: *frame,
                             pivot: super::Pivot::TopLeft,
+                            ..Default::default()
                         };
 
                         let grid = tile.tile.position * tile_size;
diff --git a/crates/lyra-scripting/src/lua/wrappers/sprite/tilemap.rs b/crates/lyra-scripting/src/lua/wrappers/sprite/tilemap.rs
index 2ffddcd..d30d8ae 100644
--- a/crates/lyra-scripting/src/lua/wrappers/sprite/tilemap.rs
+++ b/crates/lyra-scripting/src/lua/wrappers/sprite/tilemap.rs
@@ -4,7 +4,7 @@ use lyra_scripting_derive::{to_lua_convert, wrap_lua_struct};
 
 use super::LuaImageHandle;
 use crate as lyra_scripting;
-use crate::lua::wrappers::LuaVec2;
+use crate::lua::wrappers::{LuaVec2, LuaVec3};
 use crate::{
     lua::wrappers::{helpers, LuaRect},
     lyra_engine, ScriptEntity,
@@ -65,6 +65,7 @@ to_lua_convert!(
         atlas: wrap(LuaTextureAtlasHandle),
         (sprite, wrap_with=helpers::wrap_urect_using_luarect),
         (pivot, wrap_with=super::wrap_pivot_enum),
+        color: wrap(LuaVec3),
     }
 );