Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / commits / a937a25

sdl_runtime_compiler git · main

SDL3 game for running and compiling code at runtime

sdl3 c++ compiler dlopen cmake · first commit 2026-04-19 · last commit 2026-07-03 (3 months ago) · synced 3 days ago · upstream: git.ide3.de/hsnr/sdl-runtime-compiler

C++ 72.3% C 26.2%
git clone https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler.gitwget https://git.christianimmanuel.de/sdl-graphics/sdl_runtime_compiler/archive/sdl_runtime_compiler.tar.gz

Add token color With help of Claude

Christian Immanuel · 2026-05-31 20:25 · a937a25e717b821a42920934fe8085d917c8c783

 src/c_token/token_color.hpp       |  42 ++++++++++
 src/c_token/token_db.cpp          | 160 ++++++++++++++++++++++++++++----------
 src/c_token/token_db.hpp          |   2 +
 src/states/game_state.cpp         |  20 +++--
 src/systems/projectile_system.cpp |   2 +-
 src/systems/word_ai_system.cpp    |   8 +-
 src/systems/word_anim.cpp         |   2 +-
 src/text_3d/text_3d.cpp           |  13 +++-
 src/text_3d/text_3d.hpp           |   6 +-
 src/wall/wall_surfaces.cpp        |   2 +-
 10 files changed, 197 insertions(+), 60 deletions(-)

diff --git a/src/c_token/token_color.hpp b/src/c_token/token_color.hpp
new file mode 100644
index 0000000..ddec0bc
--- /dev/null
+++ b/src/c_token/token_color.hpp
@@ -0,0 +1,42 @@
+#pragma once
+#include <SDL3/SDL.h>
+#include "token.hpp"
+#include "token_db.hpp"
+#include "text_3d/text_3d.hpp"
+
+namespace TokenColor
+{
+inline SDL_FColor
+get(TokenType t)
+{
+    switch (t) {
+        case TokenType::Keyword:    return Text3d::color_orange;   // if, else, while, for, return
+        case TokenType::Type:       return Text3d::color_green;    // int, float, char, void
+        case TokenType::Identifier: return Text3d::color_light_gray;    // main, printf, i, x …
+        case TokenType::Literal:    return Text3d::color_red;      // 0, 1, "\n", %s
+        case TokenType::Operator:   return Text3d::color_light_gray;    // = == + - * / ++ 
+        case TokenType::Delimiter:  return Text3d::color_light_gray;    // ( ) { } ; , [ ]
+    }
+    return Text3d::color_white;
+}
+
+inline void
+apply(Text3d* word)
+{
+    if (!word) return;
+    const Token* tok = TokenDB::find(word->text);
+    if (tok)
+        word->set_Color(get(tok->type));
+}
+
+inline SDL_FColor
+get_ByString(std::string token_text)
+{
+    const Token* tok = TokenDB::find(token_text);
+    if (tok)
+        return get(tok->type);
+    else
+        return Text3d::color_white;
+}
+
+}
diff --git a/src/c_token/token_db.cpp b/src/c_token/token_db.cpp
index f99a444..e69081e 100644
--- a/src/c_token/token_db.cpp
+++ b/src/c_token/token_db.cpp
@@ -1,50 +1,119 @@
 #include "token_db.hpp"
 #include <unordered_map>
 
+
 static const DynArray<Token>
 all_tokens = {
-    { "int",    TokenType::Type,       "Integer type",         "Declares a 32-bit integer variable" },
-    { "float",  TokenType::Type,       "Float type",           "Declares a floating point variable" },
-    { "char",   TokenType::Type,       "Character type",       "Declares a single character"        },
-    { "void",   TokenType::Type,       "No value type",        "Function returns nothing"           },
-
-    { "return", TokenType::Keyword,    "Return statement",     "Ends function and returns a value"  },
-    { "if",     TokenType::Keyword,    "Conditional branch",   "Executes code if condition is true" },
-    { "else",   TokenType::Keyword,    "Alternative branch",   "Executes if 'if' condition is false"},
-    { "while",  TokenType::Keyword,    "While loop",           "Repeats while condition is true"    },
-    { "for",    TokenType::Keyword,    "For loop",             "Loop with init, condition, increment"},
-
-    { "main",   TokenType::Identifier, "Entry point",          "First function called by the OS"    },
-    { "x",      TokenType::Identifier, "Variable name",        "Stores a value"                     },
-    { "func",   TokenType::Identifier, "Function name",        "A callable block of code"           },
-    { "printf",   TokenType::Identifier, "Print formatted",     "Outputs formatted text to stdout"  },
-    { "strlen",   TokenType::Identifier, "String length",       "Returns length of a string"        },
-    { "src",      TokenType::Identifier, "Source variable",     "Input data"                        },
-    { "dst",      TokenType::Identifier, "Destination variable","Output data"                       },
-    { "i",        TokenType::Identifier, "Loop counter",        "Common loop index variable"        },
-
-    { "0",      TokenType::Literal,    "Integer zero",         "The integer constant 0"             },
-    { "1",      TokenType::Literal,    "Integer one",          "The integer constant 1"             },
-    { "\"\\n\"",  TokenType::Literal,    "Newline string",      "String containing a newline character"      },
-    { "%s",       TokenType::Literal,    "String format",       "Printf format specifier for strings"        },
-
-    { "=",      TokenType::Operator,   "Assignment",           "Assigns a value to a variable"      },
-    { "==",     TokenType::Operator,   "Equality check",       "Compares two values"                },
-    { "+",      TokenType::Operator,   "Addition",             "Adds two values"                    },
-    { "-",      TokenType::Operator,   "Subtraction",          "Subtracts right from left"          },
-    { "*",      TokenType::Operator,   "Multiplication",       "Multiplies two values"              },
-    { "/",      TokenType::Operator,   "Division",             "Divides left by right"              },
-    { "++",       TokenType::Operator,   "Increment",           "Increases value by 1"              },
-    { "<",        TokenType::Operator,   "Less than",           "Compares two values"               },
-
-    { "(",      TokenType::Delimiter,  "Open parenthesis",     "Starts a function call or condition"},
-    { ")",      TokenType::Delimiter,  "Close parenthesis",    "Ends a function call or condition"  },
-    { "{",      TokenType::Delimiter,  "Open brace",           "Starts a code block"                },
-    { "}",      TokenType::Delimiter,  "Close brace",          "Ends a code block"                  },
-    { ";",      TokenType::Delimiter,  "Statement terminator", "Ends a statement"                   },
-    { ",",      TokenType::Delimiter,  "Separator",            "Separates function arguments"       },
-    { "[",        TokenType::Delimiter,  "Open bracket",        "Start array subscript"             },
-    { "]",        TokenType::Delimiter,  "Close bracket",       "End array subscript"               },
+    { "int",    TokenType::Type,       "Integer type",        "Declares a 32-bit integer variable"  },
+    { "float",  TokenType::Type,       "Float type",          "Declares a floating point variable"  },
+    { "char",   TokenType::Type,       "Character type",      "Declares a single character"         },
+    { "void",   TokenType::Type,       "No value type",       "Function returns nothing"            },
+    { "bool",      TokenType::Type, "Boolean type",           "Stores true or false values"                  },
+    { "short",     TokenType::Type, "Short integer type",     "Declares a short integer variable"            },
+    { "long",      TokenType::Type, "Long integer type",      "Declares a long integer variable"             },
+    { "unsigned",  TokenType::Type, "Unsigned modifier",      "Declares an unsigned integer type"            },
+    { "signed",    TokenType::Type, "Signed modifier",        "Declares a signed integer type"               },
+    { "double",    TokenType::Type, "Double type",            "Declares a double-precision floating point variable" },
+    { "wchar_t",   TokenType::Type, "Wide character type",    "Stores wide character values"                 },
+    { "char8_t",   TokenType::Type, "UTF-8 character type",   "Stores a UTF-8 code unit"                     },
+    { "char16_t",  TokenType::Type, "UTF-16 character type",  "Stores a UTF-16 code unit"                    },
+    { "char32_t",  TokenType::Type, "UTF-32 character type",  "Stores a UTF-32 code unit"                    },
+    { "size_t",    TokenType::Type, "Size type",              "Stores object sizes and array indices"        },
+    { "struct",    TokenType::Type, "Structure type",         "Defines a structure type"                     },
+    { "union",     TokenType::Type, "Union type",             "Defines a union type"                         },
+    { "enum",      TokenType::Type, "Enumeration type",       "Defines an enumeration type"                  },
+    { "typedef",   TokenType::Type, "Type alias",             "Creates an alias for a type"                  },
+    { "extern",    TokenType::Type, "External linkage",       "Declares a symbol defined elsewhere"          },
+    { "static",    TokenType::Type, "Static storage",         "Declares static storage duration"             },
+    { "register",  TokenType::Type, "Register storage",       "Hints that a variable is frequently used"     },
+    { "volatile",  TokenType::Type, "Volatile qualifier",     "Prevents certain compiler optimizations"      },
+    { "const",     TokenType::Type, "Constant qualifier",     "Prevents modification of an object"           },
+
+    { "return",    TokenType::Keyword, "Return statement",    "Ends function and returns a value"   },
+    { "if",        TokenType::Keyword, "Conditional branch",  "Executes code if condition is true"  },
+    { "else",      TokenType::Keyword, "Alternative branch",  "Executes if 'if' condition is false" },
+    { "while",     TokenType::Keyword, "While loop",          "Repeats while condition is true"     },
+    { "for",       TokenType::Keyword, "For loop",            "Loop with init, condition, increment"},
+    { "switch",    TokenType::Keyword, "Switch statement",    "Selects execution path based on a value"      },
+    { "case",      TokenType::Keyword, "Case label",          "Marks a branch in a switch statement"         },
+    { "default",   TokenType::Keyword, "Default label",       "Fallback branch in a switch statement"        },
+    { "break",     TokenType::Keyword, "Break statement",     "Exits a loop or switch statement"             },
+    { "continue",  TokenType::Keyword, "Continue statement",  "Skips to the next loop iteration"             },
+    { "goto",      TokenType::Keyword, "Goto statement",      "Jumps to a labeled statement"                 },
+    { "do",        TokenType::Keyword, "Do loop",             "Begins a do-while loop"                        },
+    { "sizeof",    TokenType::Keyword, "Size operator",       "Returns the size of a type or object"         },
+
+    { "main",   TokenType::Identifier, "Entry point",         "First function called by the OS"     },
+    { "x",      TokenType::Identifier, "Variable name",       "Stores a value"                      },
+    { "y",      TokenType::Identifier, "Variable name",       "Stores a value"                      },
+    { "z",      TokenType::Identifier, "Variable name",       "Stores a value"                      },
+    { "func",   TokenType::Identifier, "Function name",       "A callable block of code"            },
+    { "printf", TokenType::Identifier, "Print formatted",     "Outputs formatted text to stdout"    },
+    { "strlen", TokenType::Identifier, "String length",       "Returns length of a string"          },
+    { "src",    TokenType::Identifier, "Source variable",     "Input data"                          },
+    { "dst",    TokenType::Identifier, "Destination variable","Output data"                         },
+    { "i",      TokenType::Identifier, "Loop counter",        "Common loop index variable"          },
+    { "j",      TokenType::Identifier, "Loop counter",        "Common loop index variable"          },
+    { "k",      TokenType::Identifier, "Loop counter",        "Common loop index variable"          },
+
+    { "NULL",   TokenType::Literal,    "Integer zero",        "The integer constant 0"              },
+    { "0",      TokenType::Literal,    "Integer zero",        "The integer constant 0"              },
+    { "1",      TokenType::Literal,    "Integer one",         "The integer constant 1"              },
+    { "\"\\n\"",TokenType::Literal,    "Newline string",      "String containing a newline character"},
+    { "%s",     TokenType::Literal,    "String format",       "Printf format specifier for strings" },
+    { "\"",     TokenType::Literal,    "Double quote character","Quotation mark character (\")" },
+    { "'",      TokenType::Literal,    "Single quote character","Apostrophe or character literal delimiter" },
+    { "true",   TokenType::Literal,    "Boolean true",        "Boolean constant true"                   },
+    { "false",  TokenType::Literal,    "Boolean false",       "Boolean constant false"                  },
+    { "%d",     TokenType::Literal,    "Integer format",      "Printf format specifier for integers"    },
+    { "%u",     TokenType::Literal,    "Unsigned format",     "Printf format specifier for unsigned integers" },
+    { "%f",     TokenType::Literal,    "Float format",        "Printf format specifier for floating-point values" },
+    { "%c",     TokenType::Literal,    "Character format",    "Printf format specifier for characters"  },
+    { "%p",     TokenType::Literal,    "Pointer format",      "Printf format specifier for pointers"    },
+    { "%%",     TokenType::Literal,    "Percent format",      "Printf escape sequence for percent sign" },
+
+    { "!=",     TokenType::Operator, "Not equal",             "Checks whether two values differ"           },
+    { "<",      TokenType::Operator, "Less than",             "Checks whether left is less than right"  },
+    { ">",      TokenType::Operator, "Greater than",          "Checks whether left is greater than right"  },
+    { "<=",     TokenType::Operator, "Less or equal",         "Checks whether left is less than or equal to right" },
+    { ">=",     TokenType::Operator, "Greater or equal",      "Checks whether left is greater than or equal to right" },
+    { "--",     TokenType::Operator, "Decrement",             "Decreases value by 1"                       },
+    { "+=",     TokenType::Operator, "Addition assignment",   "Adds and assigns the result"                },
+    { "-=",     TokenType::Operator, "Subtraction assignment","Subtracts and assigns the result"           },
+    { "*=",     TokenType::Operator, "Multiplication assignment", "Multiplies and assigns the result"      },
+    { "/=",     TokenType::Operator, "Division assignment",   "Divides and assigns the result"             },
+    { "%=",     TokenType::Operator, "Modulo assignment",     "Calculates remainder and assigns it"        },
+    { "%",      TokenType::Operator, "Modulo",                "Returns the division remainder"             },
+    { "&&",     TokenType::Operator, "Logical AND",           "True if both operands are true"             },
+    { "||",     TokenType::Operator, "Logical OR",            "True if either operand is true"             },
+    { "!",      TokenType::Operator, "Logical NOT",           "Inverts a boolean value"                    },
+    { "&",      TokenType::Operator, "Bitwise AND",           "Performs bitwise conjunction"               },
+    { "|",      TokenType::Operator, "Bitwise OR",            "Performs bitwise disjunction"               },
+    { "^",      TokenType::Operator, "Bitwise XOR",           "Performs bitwise exclusive OR"              },
+    { "~",      TokenType::Operator, "Bitwise NOT",           "Inverts all bits"                           },
+    { "<<",     TokenType::Operator, "Left shift",            "Shifts bits to the left"                    },
+    { ">>",     TokenType::Operator, "Right shift",           "Shifts bits to the right"                   },
+    { "<<=",    TokenType::Operator, "Left shift assignment", "Left shifts and assigns the result"         },
+    { ">>=",    TokenType::Operator, "Right shift assignment","Right shifts and assigns the result"        },
+    { "&=",     TokenType::Operator, "AND assignment",        "Performs bitwise AND and assigns"           },
+    { "|=",     TokenType::Operator, "OR assignment",         "Performs bitwise OR and assigns"            },
+    { "^=",     TokenType::Operator, "XOR assignment",        "Performs bitwise XOR and assigns"           },
+    { "->",     TokenType::Operator, "Member access",         "Accesses a member through a pointer"        },
+    { ".",      TokenType::Operator, "Member access",         "Accesses a member of an object"             },
+    { "?",      TokenType::Operator, "Conditional operator",  "Begins a ternary conditional expression"    },
+    { ":",      TokenType::Operator, "Conditional separator", "Separates true and false branches"          },
+    { ",",      TokenType::Operator, "Comma operator",        "Separates expressions or arguments"         },
+    { "*",      TokenType::Operator, "Dereference",           "Accesses the object pointed to by a pointer" },
+    { "&",      TokenType::Operator, "Address-of",            "Obtains the address of an object"           },
+
+    { "(",      TokenType::Delimiter,  "Open parenthesis",    "Starts a function call or condition" },
+    { ")",      TokenType::Delimiter,  "Close parenthesis",   "Ends a function call or condition"   },
+    { "{",      TokenType::Delimiter,  "Open brace",          "Starts a code block"                 },
+    { "}",      TokenType::Delimiter,  "Close brace",         "Ends a code block"                   },
+    { ";",      TokenType::Delimiter,  "Statement terminator","Ends a statement"                    },
+    { ",",      TokenType::Delimiter,  "Separator",           "Separates function arguments"        },
+    { "[",      TokenType::Delimiter,  "Open bracket",        "Start array subscript"               },
+    { "]",      TokenType::Delimiter,  "Close bracket",       "End array subscript"                 },
 
 };
 
@@ -63,6 +132,13 @@ static const std::unordered_map<std::string, const Token*>
 token_index = build_index();
 
 
+DynArray<std::string> 
+TokenDB::get_TestArrayAllKeywords()
+{
+    return { "float", "return", "main", "0", "++", "(", ",", ";", "\"", "\"" };
+}
+
+
 const Token*
 TokenDB::find(const std::string& text)
 {
diff --git a/src/c_token/token_db.hpp b/src/c_token/token_db.hpp
index 0e7268e..0bb2799 100644
--- a/src/c_token/token_db.hpp
+++ b/src/c_token/token_db.hpp
@@ -9,5 +9,7 @@ namespace TokenDB
     DynArray<const Token*> of_type(TokenType type);
     const char*            type_name(TokenType type);
 
+    DynArray<std::string>  get_TestArrayAllKeywords();
+
     bool                   known(const std::string& text);
 }
diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp
index 6a90b19..5316795 100644
--- a/src/states/game_state.cpp
+++ b/src/states/game_state.cpp
@@ -3,6 +3,7 @@
 #include <unordered_set>
 
 
+#include "c_token/token_color.hpp"
 #include "core/game.hpp"
 #include "entities/solid_box.hpp"
 #include "entities/world.hpp"
@@ -81,13 +82,15 @@ GameState::GameState(size_t starting_level)
     ));
     ctx.scenery.back()->body.mode = PhysicsMode::Dynamic;
     */
-    // debug_SpawnWords(5);
+    debug_SpawnWords(0);
 }
 
 
 void
-GameState::debug_SpawnWords(size_t n)
+GameState::debug_SpawnWords([[maybe_unused]]size_t n)
 {
+    DynArray<std::string> tokens = TokenDB::get_TestArrayAllKeywords();
+    /*
     DynArray<std::string> tokens;
     tokens.reserve(n);
     static const char* samples[] = {
@@ -96,6 +99,7 @@ GameState::debug_SpawnWords(size_t n)
     };
     for (size_t i = 0; i < n; ++i)
         tokens.push_back(samples[i % (sizeof(samples)/sizeof(samples[0]))]);
+    */
     step_Spawn(tokens);
 }
 
@@ -189,7 +193,7 @@ GameState::on_Pick()
 
         if (base->type == ObjectType::Text) {
             step_ledger.picked_up.push_back(base->text);
-            base->set_Look(Text3d::color_floor, Text3d::depth_floor);
+            base->set_Look(Text3d::color_keep, Text3d::depth_floor);
             TextWall::show_TokenInfo(ctx.wall_texts, base->text, ctx.world->scale());
         }
         carry_BeginAnim(std::move(base), /*with_pitch=*/true);
@@ -203,7 +207,7 @@ GameState::on_Pick()
         if (!word) return false;
 
         step_ledger.picked_up.push_back(word->text);
-        word->set_Look(Text3d::color_floor, Text3d::depth_floor);
+        word->set_Look(Text3d::color_keep, Text3d::depth_floor);
         TextWall::show_TokenInfo(ctx.wall_texts, word->text, ctx.world->scale());
 
         carry_BeginAnim(std::move(word), /*with_pitch=*/false);
@@ -430,7 +434,7 @@ GameState::projectile_LandOnFloor(ProjectileResult& result)
 {
     for (Text3dPtr& w : result.words) {
         if (!w || w->type != ObjectType::Text) continue;
-        w->set_Look(Text3d::color_floor, Text3d::depth_floor);
+        w->set_Look(Text3d::color_keep, Text3d::depth_floor);
         w->body.mode = PhysicsMode::Dynamic;
         w->body.vel  = result.vel;
         ctx.words.push_back(std::move(w));
@@ -444,7 +448,7 @@ GameState::projectile_LandOnWall(ProjectileResult& result)
     for (Text3dPtr& w : result.words) {
         if (!w) continue;
         if (w->type == ObjectType::Text)
-            w->set_Look(Text3d::color_wall, Text3d::depth_wall);
+            w->set_Look(Text3d::color_keep, Text3d::depth_wall);
 
         w->body.mode = PhysicsMode::Static;
         w->body.vel  = Vec3{0, 0, 0};
@@ -477,7 +481,7 @@ GameState::walltext_HandleShootDown(ProjectileResult& result,
             orphan->body.vel          = { 0.0, 1.5, 0.0 };
             orphan->body.hover_height = -static_cast<double>(ctx.world->scale()) + 1.5;
             orphan->yaw               = 0.0f;
-            orphan->set_Look(Text3d::color_floor, Text3d::depth_floor);
+            orphan->set_Look(Text3d::color_keep, Text3d::depth_floor);
             ctx.words.push_back(std::move(orphan));
             to_erase.push_back(result.wall_text_index);
         }
@@ -486,7 +490,7 @@ GameState::walltext_HandleShootDown(ProjectileResult& result,
     for (Text3dPtr& w : result.words) {
         if (!w) continue;
         if (w->type == ObjectType::Text) {
-            w->set_Look(Text3d::color_floor, Text3d::depth_floor);
+            w->set_Look(Text3d::color_keep, Text3d::depth_floor);
         }
         w->body.mode = PhysicsMode::Dynamic;
         w->body.vel  = result.vel;
diff --git a/src/systems/projectile_system.cpp b/src/systems/projectile_system.cpp
index bb669cd..56533f5 100644
--- a/src/systems/projectile_system.cpp
+++ b/src/systems/projectile_system.cpp
@@ -351,7 +351,7 @@ ProjectileSystem::launch(DynArray<Projectile>&   out,
     for (Text3dPtr& w : words) {
         if (!w) continue;
         if (w->type == ObjectType::Text)
-            w->set_Look(Text3d::color_floor, Text3d::depth_floor);
+            w->set_Look(Text3d::color_keep, Text3d::depth_floor);
 
         w->yaw = static_cast<float>(yaw);
     }
diff --git a/src/systems/word_ai_system.cpp b/src/systems/word_ai_system.cpp
index 20826a3..1ae44c2 100644
--- a/src/systems/word_ai_system.cpp
+++ b/src/systems/word_ai_system.cpp
@@ -56,12 +56,12 @@ WordAiSystem::update(DynArray<Text3dPtr>& words,
                 if (!s) continue;
                 s->body.mode = PhysicsMode::Dynamic;
                 s->body.vel  = w->body.vel * 0.5;
-                s->set_Color(Text3d::color_floor);
+                s->set_Color(s->token_info ? Text3d::color_token : Text3d::color_floor);
                 released.push_back(std::move(s));   // deferred — not words.push_back
             }
             w->ai_stolen.clear();
             w->ai_state = Text3d::Ai::Idle;
-            w->set_Color(Text3d::color_floor);
+            w->set_Color(w->token_info ? Text3d::color_token : Text3d::color_floor);
             continue;
         }
 
@@ -289,7 +289,7 @@ WordAiSystem::release_StolenWords(Text3d& w, DynArray<Text3dPtr>& out)
         if (!s) continue;
         s->body.mode = PhysicsMode::Dynamic;
         s->body.vel  = { w.body.vel.x * 0.5, 2.0, w.body.vel.z * 0.5 };
-        s->set_Color(Text3d::color_floor);
+        s->set_Color(s->token_info ? Text3d::color_token : Text3d::color_floor);
         out.push_back(std::move(s));
     }
     w.ai_stolen.clear();
@@ -344,7 +344,7 @@ WordAiSystem::enter_Idle(Text3d& w)
     w.ai_state_timer = 0.0;
     w.body.mode      = PhysicsMode::Hover;
     w.body.hover_height = w.ai_hover_height_saved;
-    w.set_Color(Text3d::color_floor);
+    w.set_Color(w.token_info ? Text3d::color_token : Text3d::color_floor);
 }
 
 
diff --git a/src/systems/word_anim.cpp b/src/systems/word_anim.cpp
index 4273741..e224443 100644
--- a/src/systems/word_anim.cpp
+++ b/src/systems/word_anim.cpp
@@ -70,7 +70,7 @@ WordAnimSystem::update(DynArray<WordAnim_Add>&    anims_add,
             drop.word->body.vel.y  = 0.0;
             drop.word->body.mode   = PhysicsMode::Dynamic;
             if (drop.word->type == ObjectType::Text)
-                drop.word->set_Look(Text3d::color_floor, Text3d::depth_floor);
+                drop.word->set_Look(Text3d::color_keep, Text3d::depth_floor);
             words.push_back(std::move(drop.word));
         }
     }
diff --git a/src/text_3d/text_3d.cpp b/src/text_3d/text_3d.cpp
index 1a1ef78..86a8157 100644
--- a/src/text_3d/text_3d.cpp
+++ b/src/text_3d/text_3d.cpp
@@ -2,6 +2,8 @@
 #include <algorithm>
 #include <cstdlib>
 
+#include "c_token/token_color.hpp"
+#include "c_token/token_db.hpp"
 #include "entities/camera.hpp"
 #include "entities/world.hpp"
 #include "rendering/gl_renderer.hpp"
@@ -17,8 +19,11 @@ Text3d::Text3d(const std::string& txt,
        : GameObject(position, ObjectType::Text,
                     CollisionShape{}, RigidBody{PhysicsMode::Hover},
                     true, true, true),
-         text(txt), color(colr), depth(dpth), scale(scle)
+         text(txt), color(colr), depth(dpth), scale(scle), token_info(TokenDB::find(text))
 {
+    if (token_info)
+        set_Color(TokenColor::get(token_info->type));
+
     rebuild_Mesh();
     body.hover_phase = (rand() % 1000) / 1000.0 * SDL_PI_D * 2.0;
 
@@ -79,7 +84,11 @@ Text3d::set_Depth(float new_depth)
 void
 Text3d::set_Look(SDL_FColor c, float new_depth)
 {
-    color = c;
+    if (c.r == -1.0f)
+        color = TokenColor::get_ByString(text);
+    else if (c.g == -1.0f) { }
+    else color = c;
+
     if (new_depth == depth) return;
     depth = new_depth;
     rebuild_Mesh();
diff --git a/src/text_3d/text_3d.hpp b/src/text_3d/text_3d.hpp
index 7825732..5ceb9fc 100644
--- a/src/text_3d/text_3d.hpp
+++ b/src/text_3d/text_3d.hpp
@@ -3,6 +3,7 @@
 #include <SDL3/SDL.h>
 #include <string>
 
+#include "c_token/token_db.hpp"
 #include "cpputils/unique_ptr.hpp"
 #include "entities/game_object.hpp"
 #include "text_3d/text_mesh.hpp"
@@ -44,6 +45,8 @@ struct Text3d final : public GameObject {
     bool   glow_enabled  { false };
     float  half_extent_y { 0.2f };
 
+    static inline constexpr SDL_FColor color_keep    = {0.0f, -1.0f, 0.0f,  1.0f};
+    static inline constexpr SDL_FColor color_token   = {-1.0f, 0.0f, 0.0f,  1.0f};
     static inline constexpr SDL_FColor color_attack  = {1.0f, 0.35f, 0.2f,  1.0f};
     static inline constexpr SDL_FColor color_flee    = {1.0f, 0.95f, 0.4f,  1.0f};
     static inline constexpr SDL_FColor color_stunned = {0.45f, 0.45f, 0.5f, 1.0f};
@@ -67,7 +70,7 @@ struct Text3d final : public GameObject {
     static inline constexpr SDL_FColor color_pink       = {1.0f,  0.45f, 0.70f, 1.0f};
     static inline constexpr SDL_FColor color_brown      = {0.55f, 0.35f, 0.20f, 1.0f};
     static inline constexpr SDL_FColor color_dark_gray  = {0.25f, 0.25f, 0.25f, 1.0f};
-    static inline constexpr SDL_FColor color_light_gray = {0.75f, 0.75f, 0.75f, 1.0f};
+    static inline constexpr SDL_FColor color_light_gray = {0.82f, 0.82f, 0.82f, 1.0f};
 
     static inline constexpr SDL_FColor color_compiler = color_white;
     static inline constexpr SDL_FColor color_floor    = color_blue;
@@ -99,6 +102,7 @@ struct Text3d final : public GameObject {
     float      half_extent{0.0f};
     float      pitch{0.0f};
     Vec3       ribbon_local{};
+    const Token* token_info;
 
 
     Text3d(const std::string& txt,
diff --git a/src/wall/wall_surfaces.cpp b/src/wall/wall_surfaces.cpp
index 0bd70cc..976d33b 100644
--- a/src/wall/wall_surfaces.cpp
+++ b/src/wall/wall_surfaces.cpp
@@ -8,7 +8,7 @@
 namespace {
 
 // Wall colors — picked to match each role's purpose.
-constexpr SDL_FColor COLOR_EDITOR   = { 0.92f, 0.88f, 0.78f, 1.0f }; // cream paper
+constexpr SDL_FColor COLOR_EDITOR   = { 0.066f, 0.113f, 0.18f, 1.0f }; // cream paper
 constexpr SDL_FColor COLOR_PROGRAM  = { 0.95f, 0.92f, 0.82f, 1.0f }; // warm ivory
 constexpr SDL_FColor COLOR_INFO     = { 0.42f, 0.52f, 0.63f, 1.0f }; // slate blue
 constexpr SDL_FColor COLOR_COMPILER = { 0.06f, 0.05f, 0.12f, 1.0f }; // deep indigo