diff --git a/src/Lib/Script/FrontEnd/Lexer.cc b/src/Lib/Script/FrontEnd/Lexer.cc
index 56da511c81a42f445e9f07574b3903a0e3ca3e95..89593f2af36b8a09f1e5d0732ed50d7842bdcd87 100644
--- a/src/Lib/Script/FrontEnd/Lexer.cc
+++ b/src/Lib/Script/FrontEnd/Lexer.cc
@@ -83,17 +83,31 @@ tokenizeFile(const char *file, TokenList *tokens, std::string *storage)
         throw std::runtime_error("Found an empty file!");
     }
 
+    auto cantBeFollowedById = [&fileContent, &loc](const std::string &type) -> void {
+        bool nextIsIdChar;
+        if (fileContent.chopNextIdChar(&nextIsIdChar); nextIsIdChar) {
+            throw std::runtime_error(loc.toString() + ": Invalid " + type +
+                                     " found, directly followed by an identifier...");
+        }
+    };
+
     for (;;) {
     global_continue:
+        /* Find a color literal? */
+        fileContent = StrV::trimL(fileContent, &trimmedAmount);
+        loc         = Location::shift(loc, trimmedAmount);
+        if (fileContent.tryChopColorLiteral(&qualifiedName, &trimmedAmount)) {
+            cantBeFollowedById("color literal");
+            tokens->push_back(Token::fromColorLit(loc, qualifiedName));
+            loc = Location::shift(loc, trimmedAmount);
+            continue;
+        }
+
         /* Find a floating? */
         fileContent = StrV::trimL(fileContent, &trimmedAmount);
         loc         = Location::shift(loc, trimmedAmount);
         if (fileContent.tryChopFloating(&floating, &trimmedAmount)) {
-            if (fileContent.chopNextIdChar(&ok); ok) {
-                throw std::runtime_error(loc.toString() +
-                                         ": Invalid floating point found, directly "
-                                         "followed by an identifier...");
-            }
+            cantBeFollowedById("floating point");
             tokens->push_back(Token::fromFloating(loc, floating));
             loc = Location::shift(loc, trimmedAmount);
             continue;
@@ -103,10 +117,7 @@ tokenizeFile(const char *file, TokenList *tokens, std::string *storage)
         fileContent = StrV::trimL(fileContent, &trimmedAmount);
         loc         = Location::shift(loc, trimmedAmount);
         if (fileContent.tryChopInteger(&integer, &trimmedAmount)) {
-            if (fileContent.chopNextIdChar(&ok); ok) {
-                throw std::runtime_error(loc.toString() + ": Invalid integer found, directly "
-                                                          "followed by an identifier...");
-            }
+            cantBeFollowedById("integer");
             tokens->push_back(Token::fromInteger(loc, integer));
             loc = Location::shift(loc, trimmedAmount);
             continue;
@@ -130,10 +141,7 @@ tokenizeFile(const char *file, TokenList *tokens, std::string *storage)
         fileContent = StrV::trimL(fileContent, &trimmedAmount);
         loc         = Location::shift(loc, trimmedAmount);
         if (fileContent.tryChopEscapedString(&qualifiedName, &trimmedAmount)) {
-            if (fileContent.chopNextIdChar(&ok); ok) {
-                throw std::runtime_error(loc.toString() + "Invalid string literal, directly "
-                                                          "followed by an identifier...");
-            }
+            cantBeFollowedById("string literal");
             tokens->push_back(Token::fromStringLit(loc, qualifiedName));
             loc = Location::shift(loc, trimmedAmount);
             continue;
diff --git a/src/Lib/Script/FrontEnd/StrV.cc b/src/Lib/Script/FrontEnd/StrV.cc
index 5c24d413e6a7ee329f145e1fb999eaaa073c98b7..60bfa036428751f444b81540c8e02d9f290c2afe 100644
--- a/src/Lib/Script/FrontEnd/StrV.cc
+++ b/src/Lib/Script/FrontEnd/StrV.cc
@@ -296,6 +296,52 @@ StrV::tryChopEscapedString(StrV *ret) noexcept
     return StrV::tryChopEscapedString(ret, &amount);
 }
 
+bool
+StrV::tryChopColorLiteral(StrV *ret) noexcept
+{
+    int amount = 0;
+    return tryChopColorLiteral(ret, &amount);
+}
+
+bool
+StrV::tryChopColorLiteral(StrV *ret, int *amount) noexcept
+{
+    // Valid colors example:
+    //      #314159
+    //      #31415900
+    //      #314159AA
+    // The amount should be 7 or 9 (`# + rgb` or `# + rgba`)
+
+    *amount = 0;
+    StrV sv = StrV::copy(*this);
+
+    if ((sv.count == 0) || (sv.data[0] != '#'))
+        return false;
+
+    *amount += 1;
+    sv.chopLeft(1);
+
+    while (sv.count && (*amount <= 8)) {
+        if (const char c = sv.data[0];
+            (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')) {
+            *amount += 1;
+            sv.chopLeft(1);
+        } else {
+            break;
+        }
+    }
+
+    if (*amount != 9 && *amount != 7) {
+        *amount = 0;
+        return false;
+    }
+
+    ret->data  = data;
+    ret->count = *amount;
+    *this      = sv;
+    return true;
+}
+
 bool
 StrV::tryChopEscapedString(StrV *ret, int *amount) noexcept
 {
diff --git a/src/Lib/Script/FrontEnd/StrV.hh b/src/Lib/Script/FrontEnd/StrV.hh
index 061012c69be56ccefe1ec0d68412e1da2e8e2759..cb6ccad40fbddaf5f03f8cab143617029a0344a9 100644
--- a/src/Lib/Script/FrontEnd/StrV.hh
+++ b/src/Lib/Script/FrontEnd/StrV.hh
@@ -40,10 +40,12 @@ struct StrV final {
     bool tryChopInteger(int *) noexcept;
     bool tryChopFloating(double *) noexcept;
     bool tryChopEscapedString(StrV *) noexcept;
+    bool tryChopColorLiteral(StrV *) noexcept;
 
     bool tryChopInteger(int *, int *) noexcept;
     bool tryChopFloating(double *, int *) noexcept;
     bool tryChopEscapedString(StrV *, int *) noexcept;
+    bool tryChopColorLiteral(StrV *, int *) noexcept;
 
     /* Find substrings or characters in a string view. Returns 1 if found, 0
      * otherwise. For the index_of function the index of the character is placed
diff --git a/src/Lib/Script/FrontEnd/Token.cc b/src/Lib/Script/FrontEnd/Token.cc
index 71f6f53b4c8eec2d55351f70685cf3c0e2c5ec27..992950cddbb8da5ade4e44eb2ffc6e0438a5619b 100644
--- a/src/Lib/Script/FrontEnd/Token.cc
+++ b/src/Lib/Script/FrontEnd/Token.cc
@@ -15,6 +15,7 @@ toString(::Vivy::Script::Token::Type t) noexcept
     case ::Vivy::Script::Token::FLOATING: return std::string("FLOATING");
     case ::Vivy::Script::Token::QNAME: return std::string("QNAME");
     case ::Vivy::Script::Token::STRINGLIT: return std::string("STRINGLIT");
+    case ::Vivy::Script::Token::COLORLIT: return std::string("COLORLIT");
     }
     assert(0 && "Invalid Type was passed");
     return "";
@@ -26,12 +27,24 @@ Token::isStringLit() const noexcept
     return (unionType == STRINGLIT);
 }
 
+bool
+Token::isColorLit() const noexcept
+{
+    return (unionType == COLORLIT);
+}
+
 void
 Token::assertTypeStringLit() const
 {
     assertType(STRINGLIT);
 }
 
+void
+Token::assertTypeColorLit() const
+{
+    assertType(COLORLIT);
+}
+
 bool
 Token::isSimple(StrV sv) const noexcept
 {
@@ -99,6 +112,7 @@ Token::toString() const noexcept
     switch (unionType) {
     case SIMPLE:
     case STRINGLIT:
+    case COLORLIT:
     case QNAME: ret += value.str.toStdString(); break;
 
     case INTEGER: ret += std::to_string(value.integer); break;
@@ -173,6 +187,13 @@ Token::asStringLit() const
     return value.str;
 }
 
+StrV
+Token::asColorLit() const
+{
+    ensureUnionType(COLORLIT);
+    return value.str;
+}
+
 Token
 Token::fromStringLit(::Vivy::Script::Location loc, StrV v) noexcept
 {
@@ -182,6 +203,15 @@ Token::fromStringLit(::Vivy::Script::Location loc, StrV v) noexcept
     return ret;
 }
 
+Token
+Token::fromColorLit(::Vivy::Script::Location loc, StrV v) noexcept
+{
+    Token ret(loc);
+    ret.value.str = v;
+    ret.unionType = COLORLIT;
+    return ret;
+}
+
 Token
 Token::fromInteger(::Vivy::Script::Location loc, int v) noexcept
 {
diff --git a/src/Lib/Script/FrontEnd/Token.hh b/src/Lib/Script/FrontEnd/Token.hh
index e41e7dac993bfc9c5b606831c94412d1e4823ea2..4344986f1e5a575c0f81150ea260f735453274b7 100644
--- a/src/Lib/Script/FrontEnd/Token.hh
+++ b/src/Lib/Script/FrontEnd/Token.hh
@@ -14,6 +14,7 @@ public:
         INTEGER,
         FLOATING,
         STRINGLIT,
+        COLORLIT,
         QNAME,
     };
 
@@ -39,10 +40,12 @@ public:
     double asFloating() const;
     StrV asQName() const;
     StrV asStringLit() const;
+    StrV asColorLit() const;
 
     std::string toString() const noexcept;
 
     bool isQName() const noexcept;
+    bool isColorLit() const noexcept;
     bool isStringLit() const noexcept;
     bool isSimple(StrV) const noexcept;
     bool isSimple(const std::initializer_list<StrV> &) const noexcept;
@@ -50,9 +53,11 @@ public:
     /* Throws an exception if the Token is not of the correct Type */
     void assertType(const Type) const;
     void assertTypeStringLit() const;
+    void assertTypeColorLit() const;
     void assertTypeSimple(const StrV) const;
     void assertTypeSimple(const std::initializer_list<StrV> &) const;
 
+    static Token fromColorLit(::Vivy::Script::Location, StrV) noexcept;
     static Token fromStringLit(::Vivy::Script::Location, StrV) noexcept;
     static Token fromInteger(::Vivy::Script::Location, int) noexcept;
     static Token fromFloating(::Vivy::Script::Location, double) noexcept;