Nimbin[12]?SDL & Graphics / sdl_runtime_compiler / commits / 7dc7387

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

Cleanup Rename Refractor

Christian Immanuel · 2026-06-07 18:06 · 7dc7387602435ab71fd7c4579263e2561543cac6

 benchmark/bench_collision.cpp                |   1 +
 benchmark/bench_text_mesh.cpp                |   8 +-
 src/core/game.hpp                            |  11 +-
 src/core/main.cpp                            |   2 +-
 src/cpp_token/cpp_highlight.hpp              |  14 +-
 src/cpp_token/token.hpp                      |   6 +-
 src/cpp_token/token_db.cpp                   |   4 +-
 src/cpp_token/token_db.hpp                   |  15 +-
 src/entities/camera.hpp                      |   9 +-
 src/entities/game_object.hpp                 |  55 ++++---
 src/entities/plate.cpp                       |  10 +-
 src/entities/plate.hpp                       |   7 +-
 src/entities/pult.cpp                        |   4 +-
 src/entities/pult.hpp                        |  21 ++-
 src/entities/solid_box.hpp                   |  19 ++-
 src/entities/world.cpp                       |   3 +-
 src/entities/world.hpp                       |  15 +-
 src/levels/goal.cpp                          |  27 ++--
 src/levels/goal.hpp                          |  18 ++-
 src/levels/level.cpp                         |  44 ++++++
 src/levels/level.hpp                         |  37 +++--
 src/levels/level/char_copy.cpp               |  12 +-
 src/levels/level/sandbox.cpp                 |   2 +-
 src/levels/level/tutorial.cpp                |  48 +++---
 src/levels/level_check.cpp                   |  39 -----
 src/levels/level_check.hpp                   |  10 --
 src/levels/scene.hpp                         |  68 ++++----
 src/rendering/floor_mandelbrot.cpp           |  22 +--
 src/rendering/floor_mandelbrot.hpp           |   7 +-
 src/rendering/gl_renderer.cpp                |  49 +++---
 src/rendering/gl_renderer.hpp                | 226 ++++++++++++--------------
 src/states/game_context.cpp                  |   9 +-
 src/states/game_context.hpp                  |   8 +-
 src/states/game_state.cpp                    | 151 +++++++++---------
 src/states/game_state.hpp                    |  63 ++++----
 src/states/istate.hpp                        |   2 +
 src/states/menu_state.cpp                    |  12 +-
 src/states/menu_state.hpp                    |  18 +--
 src/systems/aim.hpp                          |  27 ++--
 src/systems/carry_system.cpp                 |   5 +
 src/systems/carry_system.hpp                 |   8 +-
 src/systems/celebration_system.cpp           |   4 +-
 src/systems/celebration_system.hpp           |  14 +-
 src/systems/collision.cpp                    |  29 ++--
 src/systems/collision.hpp                    |  14 +-
 src/systems/compiler_system.cpp              |  18 +--
 src/systems/compiler_system.hpp              |  21 +--
 src/systems/cpp_highlight_system.hpp         |  36 +++--
 src/systems/dyn_loader_system.cpp            |  18 +--
 src/systems/dyn_loader_system.hpp            |  19 +--
 src/systems/freelook_system.cpp              |   4 +-
 src/systems/freelook_system.hpp              |  14 +-
 src/systems/hint_system.hpp                  |   9 +-
 src/systems/input_system.hpp                 |  13 +-
 src/systems/level_director.cpp               |  52 +++---
 src/systems/level_director.hpp               |  35 ++--
 src/systems/level_runner_system.cpp          |   9 +-
 src/systems/level_runner_system.hpp          |  22 +--
 src/systems/particle_system.cpp              |   7 +-
 src/systems/particle_system.hpp              |  26 +--
 src/systems/physics_system.cpp               |  30 ++--
 src/systems/physics_system.hpp               |  17 +-
 src/systems/pick_system.cpp                  |   4 +-
 src/systems/pick_system.hpp                  |  15 +-
 src/systems/plate_system.cpp                 |   4 +-
 src/systems/program_system.cpp               |  26 +--
 src/systems/program_system.hpp               |  20 +--
 src/systems/projectile_system.cpp            |  24 +--
 src/systems/projectile_system.hpp            |  49 +++---
 src/systems/pult_system.cpp                  |   2 +-
 src/systems/pult_system.hpp                  |  23 +--
 src/systems/wall_connection.cpp              |  79 +++++-----
 src/systems/wall_connection.hpp              |  39 +++--
 src/systems/word_ai_system.hpp               |  40 ++---
 src/systems/word_anim.hpp                    |  17 +-
 src/text_3d/text_3d.cpp                      |  26 +--
 src/text_3d/text_3d.hpp                      |  81 +++++-----
 src/text_3d/text_file.hpp                    |  84 ----------
 src/text_3d/text_label.cpp                   |   4 +-
 src/text_3d/text_label.hpp                   |  26 +--
 src/text_3d/text_mesh.cpp                    |  61 +++----
 src/text_3d/text_mesh.hpp                    |  30 ++--
 src/text_3d/vim_buffer.cpp                   | 228 +++++++++++++++++++++++++++
 src/text_3d/vim_buffer.hpp                   | 205 +++++-------------------
 src/utils/ascii.hpp                          |  53 -------
 src/utils/carry_math.cpp                     |  13 +-
 src/utils/carry_math.hpp                     |  15 +-
 src/utils/config.hpp                         |   2 +-
 src/utils/frame_profiler.hpp                 |  31 ++--
 src/utils/globals.hpp                        |  14 +-
 src/utils/light.hpp                          |  48 ++----
 src/utils/math.hpp                           |  23 ++-
 src/utils/text.cpp                           | 165 +++++++++++++++++++
 src/utils/text.hpp                           |  49 ++++++
 src/utils/text_wrap.hpp                      |  59 -------
 src/wall/{editor_wall.cpp => editor.cpp}     |  79 +++++-----
 src/wall/{editor_wall.hpp => editor.hpp}     |  21 ++-
 src/wall/{wall_label.cpp => label.cpp}       |  24 ++-
 src/wall/{wall_surfaces.cpp => surfaces.cpp} |  64 +++++---
 src/wall/{text_wall.cpp => text.cpp}         | 116 +++++++++++---
 src/wall/text_wall.hpp                       |  23 ---
 src/wall/text_wall_scroll.hpp                |  52 ------
 src/wall/wall.cpp                            |  77 +++++++++
 src/wall/wall.hpp                            | 142 ++++++++---------
 src/wall/wall_label.hpp                      |  36 -----
 src/wall/wall_surfaces.hpp                   |  31 ----
 106 files changed, 1992 insertions(+), 1759 deletions(-)

diff --git a/benchmark/bench_collision.cpp b/benchmark/bench_collision.cpp
index 19ddff5..f9203d8 100644
--- a/benchmark/bench_collision.cpp
+++ b/benchmark/bench_collision.cpp
@@ -3,6 +3,7 @@
 
 #include "systems/collision.hpp"
 #include "entities/solid_box.hpp"
+#include "utils/globals.hpp"
 #include "utils/math.hpp"
 
 
diff --git a/benchmark/bench_text_mesh.cpp b/benchmark/bench_text_mesh.cpp
index f233032..029ffcc 100644
--- a/benchmark/bench_text_mesh.cpp
+++ b/benchmark/bench_text_mesh.cpp
@@ -14,7 +14,7 @@ static void BM_BuildTextMesh_Short(benchmark::State& state)
         out.tris.clear();
         out.vertex_normals.clear();
         benchmark::DoNotOptimize(
-            buildTextMesh(out, FONT, "if", 64, 0.14f, 0.003f)
+            out.build(FONT, "if", 64, 0.14f, 0.003f)
         );
     }
 }
@@ -29,7 +29,7 @@ static void BM_BuildTextMesh_Medium(benchmark::State& state)
         out.tris.clear();
         out.vertex_normals.clear();
         benchmark::DoNotOptimize(
-            buildTextMesh(out, FONT, "function", 64, 0.14f, 0.003f)
+            out.build(FONT, "function", 64, 0.14f, 0.003f)
         );
     }
 }
@@ -45,7 +45,7 @@ static void BM_BuildTextMesh_Length(benchmark::State& state)
         out.tris.clear();
         out.vertex_normals.clear();
         benchmark::DoNotOptimize(
-            buildTextMesh(out, FONT, text, 64, 0.14f, 0.003f)
+            out.build(FONT, text, 64, 0.14f, 0.003f)
         );
     }
     state.SetLabel("len=" + std::to_string(state.range(0)));
@@ -63,7 +63,7 @@ static void BM_BuildTextMesh_Depth(benchmark::State& state)
         out.tris.clear();
         out.vertex_normals.clear();
         benchmark::DoNotOptimize(
-            buildTextMesh(out, FONT, "hello", 64, depth, 0.003f)
+            out.build(FONT, "hello", 64, depth, 0.003f)
         );
     }
     state.SetLabel("depth=" + std::to_string(depth));
diff --git a/src/core/game.hpp b/src/core/game.hpp
index 7f5bb17..7aa3f78 100644
--- a/src/core/game.hpp
+++ b/src/core/game.hpp
@@ -4,9 +4,9 @@
 #include <cpputils/unique_ptr.hpp>
 #include <memory>
 
+#include "rendering/gl_renderer.hpp"
 #include "states/istate.hpp"
 #include "utils/globals.hpp"
-#include "rendering/gl_renderer.hpp"
 
 
 class Game
@@ -17,12 +17,11 @@ class Game
     cpputils::unique_ptr<IState> m_state;
 public:
     ~Game();
-    void change_State (cpputils::unique_ptr<IState> next);
 
+    void change_State (cpputils::unique_ptr<IState> next);
     void handle_Event (const SDL_Event& event);
-    bool init   ();
-    void update (double dt_ns);
-    void render ();
-
+    bool init     ();
+    void update   (double dt_ns);
+    void render   ();
     void shutdown ();
 };
diff --git a/src/core/main.cpp b/src/core/main.cpp
index 2b77a70..172d3db 100644
--- a/src/core/main.cpp
+++ b/src/core/main.cpp
@@ -2,7 +2,7 @@
 #include <SDL3/SDL_main.h>
 
 #include "utils/config.hpp"
-#include "utils/math.hpp"
+#include "utils/globals.hpp"
 #include "core/game.hpp"
 #include "entities/world.hpp"
 #include "entities/player.hpp"
diff --git a/src/cpp_token/cpp_highlight.hpp b/src/cpp_token/cpp_highlight.hpp
index 13e65e1..9bd26d7 100644
--- a/src/cpp_token/cpp_highlight.hpp
+++ b/src/cpp_token/cpp_highlight.hpp
@@ -3,9 +3,17 @@
 #include "cpp_token/token.hpp"
 #include "utils/globals.hpp"
 
-struct HiSpan { size_t byte_begin; size_t byte_end; TokenType type; };
 
-namespace CppHighlight {
-    DynArray<HiSpan> classify(const std::string& source);
+struct HiSpan
+{
+    size_t    byte_begin;
+    size_t    byte_end;
+    TokenType type;
+};
+
+
+namespace CppHighlight
+{
+    DynArray<HiSpan> classify     (const std::string& source);
     TokenType        classify_Word(const std::string& word);
 }
diff --git a/src/cpp_token/token.hpp b/src/cpp_token/token.hpp
index 5a1aa3a..700ff85 100644
--- a/src/cpp_token/token.hpp
+++ b/src/cpp_token/token.hpp
@@ -3,7 +3,8 @@
 #include <cstdint>
 #include <string>
 
-enum class TokenType : uint8_t {
+enum class TokenType : uint8_t
+{
     Delimiter,
     Identifier,
     Keyword,
@@ -19,7 +20,8 @@ enum class TokenType : uint8_t {
     Namespace,
 };
 
-struct Token {
+struct Token
+{
     std::string text;
     TokenType   type;
     std::string short_desc;
diff --git a/src/cpp_token/token_db.cpp b/src/cpp_token/token_db.cpp
index 457993b..e4894d0 100644
--- a/src/cpp_token/token_db.cpp
+++ b/src/cpp_token/token_db.cpp
@@ -119,7 +119,7 @@ generic_For(TokenType type)
 
 
 TokenDB::Desc
-TokenDB::describe(const std::string& text, TokenType type)
+TokenDB::get_Description(const std::string& text, TokenType type)
 {
     const auto& t = table();
     auto it = t.find(text);
@@ -130,7 +130,7 @@ TokenDB::describe(const std::string& text, TokenType type)
 
 
 const char*
-TokenDB::type_Name(TokenType t)
+TokenDB::get_TypeName(TokenType t)
 {
     switch (t) {
         case TokenType::Keyword:      return "Keyword";
diff --git a/src/cpp_token/token_db.hpp b/src/cpp_token/token_db.hpp
index 8e2d59e..dd7ee79 100644
--- a/src/cpp_token/token_db.hpp
+++ b/src/cpp_token/token_db.hpp
@@ -7,11 +7,14 @@
 
 namespace TokenDB
 {
-    struct Desc { std::string short_desc; std::string long_desc; };
+    struct Desc
+    {
+        std::string short_desc;
+        std::string long_desc;
+    };
 
-    Desc describe(const std::string& text, TokenType type);
-
-    const char* type_Name(TokenType type);
-
-    DynArray<std::string> get_TestArrayAllKeywords();
+    const char* get_TypeName   (TokenType type);
+    Desc        get_Description(const std::string& text, TokenType type);
+    DynArray<std::string>
+                get_TestArrayAllKeywords();
 }
diff --git a/src/entities/camera.hpp b/src/entities/camera.hpp
index aa8f82b..94be3be 100644
--- a/src/entities/camera.hpp
+++ b/src/entities/camera.hpp
@@ -2,11 +2,12 @@
 
 #include <SDL3/SDL.h>
 
-#include "utils/config.hpp"
-#include "utils/math.hpp"
 #include "entities/player.hpp"
+#include "utils/config.hpp"
+#include "utils/globals.hpp"
 
-struct Camera {
+struct Camera
+{
     int32_t  pitch  {};
     uint32_t yaw    {};
     double   yaw_r  {};
@@ -16,7 +17,7 @@ struct Camera {
     Vec3 fwd  {};
     Vec3 right{};
 
-    void syncFromPlayer(const Player& player)
+    void sync_FromPlayer(const Player& player)
     {
         pos   = player.prev_pos;
         yaw   = player.yaw;
diff --git a/src/entities/game_object.hpp b/src/entities/game_object.hpp
index 33bc68c..e3a1888 100644
--- a/src/entities/game_object.hpp
+++ b/src/entities/game_object.hpp
@@ -1,21 +1,23 @@
 #pragma once
-#include <memory>
+
 #include <SDL3/SDL.h>
 
+#include "utils/globals.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
 
 class Camera;
 class GlRenderer;
 
 
-enum class ObjectType : uint8_t {
+enum class ObjectType : uint8_t
+{
     Text,
     Prop,
 };
 
 
-enum class PhysicsMode : uint8_t {
+enum class PhysicsMode : uint8_t
+{
     AiHover,
     Carried,
     Dynamic,
@@ -25,12 +27,14 @@ enum class PhysicsMode : uint8_t {
 };
 
 
-struct CollisionShape {
+struct CollisionShape
+{
     Vec3 half_extents{0.5, 0.5, 0.5};
 };
 
 
-struct RigidBody {
+struct RigidBody
+{
     bool        hover_disturbed{false};
     double      friction    {0.8};
     double      hover_height{0.0};
@@ -39,8 +43,7 @@ struct RigidBody {
     double      restitution {0.3};
     Vec3        vel  {};
     Vec3        force{};
-
-    PhysicsMode mode{PhysicsMode::Hover};
+    PhysicsMode mode {PhysicsMode::Hover};
 
 
     RigidBody(PhysicsMode m = PhysicsMode::Hover,
@@ -50,15 +53,18 @@ struct RigidBody {
             ) : friction(friction_),
                 mass(mass_),
                 restitution(restitution_),
-                mode(m) {}
+                mode(m)
+    {}
 
-    void apply_Force(const Vec3& f) {
+    void apply_Force(const Vec3& f)
+    {
         force.x += f.x;
         force.y += f.y;
         force.z += f.z;
     }
 
-    void apply_KickImpulse(const Vec3& impulse) {
+    void apply_KickImpulse(const Vec3& impulse)
+    {
         if ( mode == PhysicsMode::Hover ||
              mode == PhysicsMode::AiHover) {
             mode = PhysicsMode::Dynamic;
@@ -69,7 +75,8 @@ struct RigidBody {
         }
     }
 
-    void integrate(double dt) {
+    void integrate(double dt)
+    {
         if (mode != PhysicsMode::Dynamic) return;
         vel.x += (force.x / mass) * dt;
         vel.y += (force.y / mass) * dt;
@@ -79,7 +86,8 @@ struct RigidBody {
 };
 
 
-struct GameObject {
+struct GameObject
+{
     bool  carriable    {true};
     bool  interactable {true};
     bool  solid        {true};
@@ -93,25 +101,28 @@ struct GameObject {
 
     GameObject() {}
 
-    // c = carriable, a = active, i = interactable, s = solid
     GameObject(Vec3 p, ObjectType t, CollisionShape sh, RigidBody b,
                bool c = true, bool i = true, bool s = true)
         : carriable(c), interactable(i), solid(s),
           pos(p), type(t), shape(sh), body(b) {}
 
-    virtual ~GameObject() = default;
-    virtual void draw(GlRenderer&, const Camera&, const Light&) const = 0;
+    virtual
+         ~GameObject() = default;
+    virtual void
+         draw       (GlRenderer&, const Camera&, const Light&) const = 0;
 
-    Vec3 aabb_min() const {
-        const double c = std::abs(SDL_cos(yaw));
-        const double s = std::abs(SDL_sin(yaw));
+    Vec3 aabb_Min   () const
+    {
+        const double c = SDL_fabs(SDL_cosf(yaw));
+        const double s = SDL_fabs(SDL_sinf(yaw));
         const double ex = shape.half_extents.x * c + shape.half_extents.z * s;
         const double ez = shape.half_extents.x * s + shape.half_extents.z * c;
         return { pos.x - ex, pos.y - shape.half_extents.y, pos.z - ez };
     }
-    Vec3 aabb_max() const {
-        const double c = std::abs(SDL_cos(yaw));
-        const double s = std::abs(SDL_sin(yaw));
+    Vec3 aabb_Max   () const
+    {
+        const double c  = SDL_fabs(SDL_cosf(yaw));
+        const double s  = SDL_fabs(SDL_sinf(yaw));
         const double ex = shape.half_extents.x * c + shape.half_extents.z * s;
         const double ez = shape.half_extents.x * s + shape.half_extents.z * c;
         return { pos.x + ex, pos.y + shape.half_extents.y, pos.z + ez };
diff --git a/src/entities/plate.cpp b/src/entities/plate.cpp
index 091fc04..d41ff45 100644
--- a/src/entities/plate.cpp
+++ b/src/entities/plate.cpp
@@ -1,8 +1,9 @@
-#include "plate.hpp"
-
 #include <SDL3/SDL.h>
-#include "rendering/gl_renderer.hpp"
+
 #include "entities/camera.hpp"
+#include "plate.hpp"
+#include "rendering/gl_renderer.hpp"
+
 
 void
 Plate::tick(double dt)
@@ -18,6 +19,7 @@ Plate::tick(double dt)
     was_active = active;
 }
 
+
 void
 Plate::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
 {
@@ -26,7 +28,7 @@ Plate::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
     const float hz = static_cast<float>(shape.half_extents.z);
 
     Mat4 view  = buildViewMat4(cam);
-    Mat4 proj  = gl.projection();
+    Mat4 proj  = gl.get_Projection();
     Mat4 model = buildModelMat4(pos, yaw);
     Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
 
diff --git a/src/entities/plate.hpp b/src/entities/plate.hpp
index 445e136..47834d2 100644
--- a/src/entities/plate.hpp
+++ b/src/entities/plate.hpp
@@ -4,7 +4,7 @@
 
 #include "entities/solid_box.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
+#include "utils/globals.hpp"
 
 class Camera;
 class GlRenderer;
@@ -27,11 +27,10 @@ struct Plate final : public SolidBox
               Vec3{ _HALF_W, _HALF_H, _HALF_D },
               SDL_FColor{ 0.3f, 1.0f, 0.6f, 1.0f },
               SDL_FColor{ 0.6f, 1.0f, 0.8f, 1.0f },
-              false)
-        , base_pos(world_pos)
+              false),
+        base_pos(world_pos)
     {}
 
     void tick(double dt);
-
     void draw(GlRenderer& gl, const Camera& cam, const Light& light) const override;
 };
diff --git a/src/entities/pult.cpp b/src/entities/pult.cpp
index 03444c6..e0521b5 100644
--- a/src/entities/pult.cpp
+++ b/src/entities/pult.cpp
@@ -31,7 +31,7 @@ void
 PultButton::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
 {
     Mat4 view  = buildViewMat4(cam);
-    Mat4 proj  = gl.projection();
+    Mat4 proj  = gl.get_Projection();
     Mat4 model = buildModelMat4(pos, yaw);
     Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
 
@@ -83,7 +83,7 @@ void
 Pult::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
 {
     Mat4 view  = buildViewMat4(cam);
-    Mat4 proj  = gl.projection();
+    Mat4 proj  = gl.get_Projection();
     Mat4 model = buildModelMat4(pos, yaw);
     Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
 
diff --git a/src/entities/pult.hpp b/src/entities/pult.hpp
index 5983119..82e4c68 100644
--- a/src/entities/pult.hpp
+++ b/src/entities/pult.hpp
@@ -6,7 +6,6 @@
 #include "text_3d/text_label.hpp"
 #include "utils/globals.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
 
 class Camera;
 class GlRenderer;
@@ -35,21 +34,21 @@ struct PultButton final : public SolidBox
     PultButton(const std::string& lbl, PultAction act, Vec3 world_pos);
 
     void press();
-
-    void tick(double dt);
-    void draw(GlRenderer& gl, const Camera& cam, const Light& light) const override;
+    void tick (double dt);
+    void draw (GlRenderer& gl, const Camera& cam, const Light& light) const override;
 };
 
 
 struct Pult : public SolidBox
 {
-    std::string              name;
-    DynArray<PultButton*> buttons;
-    TextLabel                label;
-
-    static constexpr float W = 0.50f;   // default half-width  (X)
-    static constexpr float H = 0.28f;   // half-height (Y)
-    static constexpr float D = 0.40f;   // default half-depth  (Z)
+    std::string name;
+    TextLabel   label;
+    DynArray<PultButton*>
+                buttons;
+
+    static constexpr float W = 0.50f;
+    static constexpr float H = 0.28f;
+    static constexpr float D = 0.40f;
 
     float half_w { W };
     float half_d { D };
diff --git a/src/entities/solid_box.hpp b/src/entities/solid_box.hpp
index 0e5dac8..dc91f5b 100644
--- a/src/entities/solid_box.hpp
+++ b/src/entities/solid_box.hpp
@@ -1,10 +1,9 @@
 #pragma once
 
+#include "entities/camera.hpp"
 #include "entities/game_object.hpp"
 #include "rendering/gl_renderer.hpp"
-#include "entities/camera.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
 
 struct SolidBox : public GameObject
 {
@@ -31,16 +30,16 @@ struct SolidBox : public GameObject
         const float hy = static_cast<float>(shape.half_extents.y);
         const float hz = static_cast<float>(shape.half_extents.z);
 
-        Mat4 view  = buildViewMat4(cam);
-        Mat4 proj  = gl.projection();
-        Mat4 model = buildModelMat4(pos, yaw);
-        Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
+        Mat4 view  = buildViewMat4    (cam);
+        Mat4 model = buildModelMat4   (pos, yaw);
+        Mat4 proj  = gl.get_Projection();
+        Mat4 mvp   = Mat4::mul        (proj, Mat4::mul(view, model));
 
         gl.set_Wireframe(false);
-        gl.set_MVP(model, mvp);
+        gl.set_MVP      (model, mvp);
         gl.set_NormalMat(model);
-        gl.set_Light(light);
-        gl.set_Color(fill_color.r, fill_color.g, fill_color.b);
-        gl.draw_Box(hx, hy, hz);
+        gl.set_Light    (light);
+        gl.set_Color    (fill_color.r, fill_color.g, fill_color.b);
+        gl.draw_Box     (hx, hy, hz);
     }
 };
diff --git a/src/entities/world.cpp b/src/entities/world.cpp
index e657f51..63818a5 100644
--- a/src/entities/world.cpp
+++ b/src/entities/world.cpp
@@ -1,5 +1,6 @@
 #include "entities/world.hpp"
 
+
 World::World()
 {
     // initEdges();
@@ -53,7 +54,7 @@ void
 World::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
 {
     Mat4 view  = buildViewMat4(camera);
-    Mat4 proj  = gl.projection();
+    Mat4 proj  = gl.get_Projection();
     Mat4 model = Mat4::identity();
     Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
 
diff --git a/src/entities/world.hpp b/src/entities/world.hpp
index f244aef..583a205 100644
--- a/src/entities/world.hpp
+++ b/src/entities/world.hpp
@@ -4,10 +4,11 @@
 
 #include "entities/player.hpp"
 #include "rendering/gl_renderer.hpp"
-#include "wall/wall_surfaces.hpp"
+#include "wall/wall.hpp"
 
 
-struct SweepResult {
+struct SweepResult
+{
     Vec3 pos;
     Vec3 vel;
     bool hit_x{};
@@ -15,16 +16,18 @@ struct SweepResult {
     bool hit_z{};
 };
 
-class World {
-    WallSurfaces _wall_surfaces;
+
+class World
+{
+    Wall::Surfaces _wall_surfaces;
 public:
     World();
 
+    void draw(GlRenderer& gl, const Camera& camera, const Light& light) const;
+
     PlayerCollision
          resolve_Player(const Player& player) const;
 
-    void draw(GlRenderer& gl, const Camera& camera, const Light& light) const;
-
     Vec3 get_SpawnPoint() const;
 
     template <typename T = float>
diff --git a/src/levels/goal.cpp b/src/levels/goal.cpp
index 2c029eb..67a49a7 100644
--- a/src/levels/goal.cpp
+++ b/src/levels/goal.cpp
@@ -1,10 +1,10 @@
-#include "goal.hpp"
-#include "level_check.hpp"
-
 #include <algorithm>
 
+#include "goal.hpp"
+#include "level.hpp"
+
 
-namespace {
+namespace Goal {
 
 bool
 contains(const DynArray<std::string>& v, const std::string& s)
@@ -18,11 +18,9 @@ contains(const DynArray<PultAction>& v, PultAction a)
     return std::find(v.begin(), v.end(), a) != v.end();
 }
 
-} // namespace
-
 
 bool
-goal_Satisfied(const Goal& g, const GoalContext& ctx)
+is_Satisfied(const Type& g, const Context& ctx)
 {
     return std::visit([&ctx](const auto& concrete) -> bool {
         using T = std::decay_t<decltype(concrete)>;
@@ -47,17 +45,17 @@ goal_Satisfied(const Goal& g, const GoalContext& ctx)
         else if constexpr (std::is_same_v<T, CompilePattern>) {
             if (!ctx.compile_ok_this_step) return false;
             if (concrete.pattern.empty())  return true;
-            return LevelCheck::contains_pattern(ctx.editor_normalized,
+            return Level::Check::contains_Pattern(ctx.editor_normalized,
                                                 concrete.pattern);
         }
         else if constexpr (std::is_same_v<T, AnyOf>) {
-            for (const Goal& sub : concrete.options)
-                if (goal_Satisfied(sub, ctx)) return true;
+            for (const Type& sub : concrete.options)
+                if (Goal::is_Satisfied(sub, ctx)) return true;
             return false;
         }
         else if constexpr (std::is_same_v<T, AllOf>) {
-            for (const Goal& sub : concrete.options)
-                if (!goal_Satisfied(sub, ctx)) return false;
+            for (const Type& sub : concrete.options)
+                if (!Goal::is_Satisfied(sub, ctx)) return false;
             return !concrete.options.empty();
         }
         else if constexpr (std::is_same_v<T, AiWordDefeated>) {
@@ -66,7 +64,10 @@ goal_Satisfied(const Goal& g, const GoalContext& ctx)
             return contains(ctx.ai_words_defeated_this_step, concrete.text);
         }
         else {
-            static_assert(sizeof(T) == 0, "Unhandled Goal alternative");
+            static_assert(sizeof(T) == 0, "Unhandled Type alternative");
         }
     }, g);
 }
+
+
+} // namespace Type
diff --git a/src/levels/goal.hpp b/src/levels/goal.hpp
index 46e458e..de5137e 100644
--- a/src/levels/goal.hpp
+++ b/src/levels/goal.hpp
@@ -7,6 +7,9 @@
 #include "utils/globals.hpp"
 
 
+namespace Goal
+{
+
 struct ReachPlate    { std::string tag; };
 struct PressButton   { PultAction action; };
 struct CollectWord   { std::string text; };
@@ -20,7 +23,7 @@ struct AnyOf;
 struct AllOf;
 
 
-using Goal = std::variant<
+using Type = std::variant<
     ReachPlate,
     PressButton,
     CollectWord,
@@ -33,15 +36,12 @@ using Goal = std::variant<
 >;
 
 
-// Composition: any one option satisfies the goal.
-struct AnyOf { DynArray<Goal> options; };
+struct AnyOf { DynArray<Type> options; };
 
-// Composition: all options must hold simultaneously.
-// Empty AllOf{} is intentionally unsatisfiable.
-struct AllOf { DynArray<Goal> options; };
+struct AllOf { DynArray<Type> options; };
 
 
-struct GoalContext {
+struct Context {
     DynArray<std::string> active_plate_tags;
     DynArray<PultAction>  buttons_pressed_this_step;
     DynArray<std::string> picked_up_this_step;
@@ -55,4 +55,6 @@ struct GoalContext {
 };
 
 
-bool goal_Satisfied(const Goal& g, const GoalContext& ctx);
+bool is_Satisfied(const Type& g, const Context& ctx);
+
+} // namespace Goal
diff --git a/src/levels/level.cpp b/src/levels/level.cpp
new file mode 100644
index 0000000..294adeb
--- /dev/null
+++ b/src/levels/level.cpp
@@ -0,0 +1,44 @@
+#include <cctype>
+
+#include "level.hpp"
+
+namespace Level
+{
+
+namespace Check
+{
+
+    std::string
+    normalize(const std::string& s)
+    {
+        std::string out;
+        out.reserve(s.size());
+
+        bool last_space = true;
+        for (char c : s) {
+            if (std::isspace(static_cast<unsigned char>(c))) {
+                if (!last_space) {
+                    out += ' ';
+                    last_space = true;
+                }
+            }
+            else {
+                out += c;
+                last_space = false;
+            }
+        }
+        if (!out.empty() && out.back() == ' ')
+            out.pop_back();
+        return out;
+    }
+
+    bool
+    contains_Pattern(const std::string& haystack, const std::string& needle)
+    {
+        if (needle.empty()) return true;
+        std::string norm_needle = normalize(needle);
+        return haystack.find(norm_needle) != std::string::npos;
+    }
+
+} // namespace Check
+} // namespace Level
diff --git a/src/levels/level.hpp b/src/levels/level.hpp
index eb9dcc7..0adf036 100644
--- a/src/levels/level.hpp
+++ b/src/levels/level.hpp
@@ -9,9 +9,18 @@
 
 namespace Level
 {
-    struct TokenGrant {
-        DynArray<std::string> choices;
+    namespace Check
+    {
+        std::string normalize(const std::string& s);
+        bool        contains_Pattern(const std::string& haystack,
+                                     const std::string& needle);
+    }
+
 
+    struct TokenGrant
+    {
+        DynArray<std::string>
+             choices;
         static TokenGrant give(const std::string& text)
                             { return { { text } }; }
         static TokenGrant choice(std::initializer_list<std::string> options)
@@ -19,12 +28,13 @@ namespace Level
     };
 
 
-    struct Step {
-        bool  reset_carry  = false;
-        int   max_ai_words = 5;
+    struct Step
+    {
+        bool reset_carry  = false;
+        int  max_ai_words = 5;
 
-        Scene scene;
-        Goal  goal = AllOf{};
+        Scene::Data scene;
+        Goal::Type  goal = Goal::AllOf{};
 
         std::string hint;
         std::string details;
@@ -33,7 +43,8 @@ namespace Level
     };
 
 
-    struct Data {
+    struct Data
+    {
         bool dynamic_lib = false;
 
         std::string name;
@@ -47,16 +58,18 @@ namespace Level
     extern Data build_Sandbox ();
     extern Data build_Tutorial();
 
-    inline const DynArray<Data> levels =
-    {
+    inline const DynArray<Data>
+    levels = {
         build_CharCopy(),
         build_Sandbox (),
         build_Tutorial(),
     };
 
-    inline const Data& get_Level(size_t i)
+    inline const Data&
+    get_Data(size_t i)
         { return levels[i]; }
-    inline size_t level_Count()
+    inline size_t
+    get_Count()
         { return levels.size(); }
 
 }
diff --git a/src/levels/level/char_copy.cpp b/src/levels/level/char_copy.cpp
index db2ff62..4e579de 100644
--- a/src/levels/level/char_copy.cpp
+++ b/src/levels/level/char_copy.cpp
@@ -15,7 +15,7 @@ Level::build_CharCopy()
                 .reset_carry  = false,
                 .max_ai_words = 3,
                 .scene        = {},
-                .goal         = CompilePattern{ "int main ( void ) { return 0 ; }" },
+                .goal         = Goal::CompilePattern{ "int main ( void ) { return 0 ; }" },
                 .hint    = "Build a working main()",
                 .details = R"(C programs start at main().
 
@@ -46,7 +46,7 @@ Grab tokens and arrange them on the editor wall.)",
                 .reset_carry  = false,
                 .max_ai_words = 3,
                 .scene        = {},
-                .goal         = CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { }" },
+                .goal         = Goal::CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { }" },
                 .hint    = "Declare the copy_str function",
                 .details = R"(Now add a function above main().
 
@@ -85,7 +85,7 @@ Place this BEFORE main.)",
                 .reset_carry  = false,
                 .max_ai_words = 3,
                 .scene        = {},
-                .goal         = CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { int i ; }" },
+                .goal         = Goal::CompilePattern{ "void copy_str ( char src [ ] , char dst [ ] ) { int i ; }" },
                 .hint    = "Add a loop counter inside copy_str",
                 .details = R"(Inside copy_str's body, declare an integer
 to track our position in the array.
@@ -106,7 +106,7 @@ of copy_str.)",
                 .reset_carry  = false,
                 .max_ai_words = 3,
                 .scene        = {},
-                .goal         = CompilePattern{ "for ( i = 0 ; i < strlen ( src ) ; i ++ ) { }" },
+                .goal         = Goal::CompilePattern{ "for ( i = 0 ; i < strlen ( src ) ; i ++ ) { }" },
                 .hint    = "Loop through src",
                 .details = R"(Add a for loop after 'int i;'.
 
@@ -132,7 +132,7 @@ This is the loop scaffold only — the body comes next.)",
                 .reset_carry  = false,
                 .max_ai_words = 3,
                 .scene        = {},
-                .goal         = CompilePattern{ "dst [ i ] = src [ i ] ;" },
+                .goal         = Goal::CompilePattern{ "dst [ i ] = src [ i ] ;" },
                 .hint    = "Copy one character per iteration",
                 .details = R"(Inside the for loop body, copy src[i] into dst[i].
 
@@ -153,7 +153,7 @@ Goal (inside the for loop):
                 .reset_carry  = false,
                 .max_ai_words = 3,
                 .scene        = {},
-                .goal         = CompilePattern{ "char dst [ 100 ] ; copy_str ( \"hello\" , dst ) ; printf ( \"%s\" , dst ) ;" },
+                .goal         = Goal::CompilePattern{ "char dst [ 100 ] ; copy_str ( \"hello\" , dst ) ; printf ( \"%s\" , dst ) ;" },
                 .hint    = "Call copy_str and print the result",
                 .details = R"(In main(), do three things before 'return 0;':
 
diff --git a/src/levels/level/sandbox.cpp b/src/levels/level/sandbox.cpp
index 32558b4..fdcd169 100644
--- a/src/levels/level/sandbox.cpp
+++ b/src/levels/level/sandbox.cpp
@@ -15,7 +15,7 @@ Level::build_Sandbox()
                 .reset_carry  = true,
                 .max_ai_words = 0,
                 .scene        = {},
-                .goal         = AllOf{},
+                .goal         = Goal::AllOf{},
                 .hint    = "Spawn a box with box(x,y,z, hx,hy,hz);",
                 .details = R"(This level IS the code you write.
 
diff --git a/src/levels/level/tutorial.cpp b/src/levels/level/tutorial.cpp
index 4603f63..f60398f 100644
--- a/src/levels/level/tutorial.cpp
+++ b/src/levels/level/tutorial.cpp
@@ -14,7 +14,7 @@ Level::build_Tutorial()
             {
                 .reset_carry  = true,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds  = {},
                     .plates = {
                         { .pos = { 8.6, World::get_FloorY<double>() + 2.2, 0.0 }, .tag = "" },
@@ -26,7 +26,7 @@ Level::build_Tutorial()
                     },
                     .words = {},
                 },
-                .goal    = ReachPlate{ "" },
+                .goal    = Goal::ReachPlate{ "" },
                 .hint    = "Jump up the steps to the plate",
                 .details = R"(Press SPACE to jump.
 
@@ -42,7 +42,7 @@ Jump on the plate on top of the platform. )",
             {
                 .reset_carry  = true,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds  = {},
                     .plates = {
                         { .pos = { 0.0, World::get_FloorY<double>() + 1.2, 6.0 }, .tag = "" },
@@ -52,7 +52,7 @@ Jump on the plate on top of the platform. )",
                     },
                     .words  = {},
                 },
-                .goal         = ReachPlate{ "" },
+                .goal         = Goal::ReachPlate{ "" },
                 .hint    = "Look at each wall, then jump onto the plate",
                 .details = R"(Move the mouse to look around.
 
@@ -68,7 +68,7 @@ Four walls surround you:
             {
                 .reset_carry  = true,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds  = {},
                     .plates    = {},
                     .platforms = {},
@@ -76,7 +76,7 @@ Four walls surround you:
                         { .pos = { 5.0, World::get_FloorY<double>() + 1.5, 0.0 }, .text = "hello" },
                     },
                 },
-                .goal    = CollectWord{ "hello" },
+                .goal    = Goal::CollectWord{ "hello" },
                 .hint    = "Walk into the floating word and press 'e'",
                 .details = R"(Words float in the air.
 
@@ -91,7 +91,7 @@ Picked words trail in front of you as you move.
             {
                 .reset_carry  = false,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds  = {},
                     .plates    = {},
                     .platforms = {},
@@ -101,10 +101,10 @@ Picked words trail in front of you as you move.
                         { .pos = { -5.0, World::get_FloorY<double>() + 1.5, -3.0 }, .text = "pressed", },
                     },
                 },
-                .goal = AllOf{{
-                    CollectWord{ "keep" },
-                    CollectWord{ "e"    },
-                    CollectWord{ "pressed" },
+                .goal = Goal::AllOf{{
+                    Goal::CollectWord{ "keep" },
+                    Goal::CollectWord{ "e"    },
+                    Goal::CollectWord{ "pressed" },
                 }},
                 .hint    = "Keep 'e' pressed and pick up all words.",
                 .details = R"(You can carry several words at once.
@@ -118,7 +118,7 @@ They queue up in the order you grab them.)",
                 .reset_carry  = false,
                 .max_ai_words = 0,
                 .scene   = {},
-                .goal    = DroppedWord{},
+                .goal    = Goal::DroppedWord{},
                 .hint    = "Press 'q' to drop a word",
                 .details = R"('q' drops the most recently picked word.
 
@@ -138,7 +138,7 @@ putting back something you grabbed by mistake.)",
                         { .pos = {  2.0, World::get_FloorY<double>() + 1.5, -3.0 }, .text = "pressed"  },
                     },
                 },
-                .goal    = ShotWord{},
+                .goal    = Goal::ShotWord{},
                 .hint    = "LEFT CLICK to throw a word (you can keep it pressed)",
                 .details = R"(Left click throws the word at the front of your line.
 
@@ -157,7 +157,7 @@ Carrying several? Tap F to throw the WHOLE line at once.)",
                         { .pos = {  0.0, World::get_FloorY<double>() + 1.5, -3.0 }, .text = "flush",},
                     },
                 },
-                .goal    = ShotWord{},
+                .goal    = Goal::ShotWord{},
                 .hint    = "Press 'f' to flush all carried words",
                 .details = R"(Bla blub
 ...)",
@@ -167,7 +167,7 @@ Carrying several? Tap F to throw the WHOLE line at once.)",
             {
                 .reset_carry = true,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds  = {
                         {
                             .aggressiveness = 1.0,
@@ -186,7 +186,7 @@ Carrying several? Tap F to throw the WHOLE line at once.)",
                         { .pos = { 6.0, World::get_FloorY<double>() + 1.5, 1.0 }, .text = "ammo", },
                     },
                 },
-                .goal    = AllOf{{ CollectWord{ "ammo" }, AiWordDefeated{ "danger" } }},
+                .goal    = Goal::AllOf{{ Goal::CollectWord{ "ammo" }, Goal::AiWordDefeated{ "danger" } }},
                 .hint    = "Grab the ammo, then shoot the red word",
                 .details = R"(Some words turn red and chase you to steal what
 you carry.
@@ -201,7 +201,7 @@ reaches you.)",
                 .reset_carry  = true,
                 .max_ai_words = 0,
                 .scene   = {},
-                .goal    = CompilePattern{ "int main ( void ) { return 0 ; }" },
+                .goal    = Goal::CompilePattern{ "int main ( void ) { return 0 ; }" },
                 .hint    = "Build int main(void) { return 0; } and press BUILD",
                 .details = R"(Now make code.
 
@@ -237,9 +237,9 @@ press it (or press 'c' to compile).)",
                 .reset_carry  = false,
                 .max_ai_words = 0,
                 .scene = {},
-                .goal  = AllOf{{
-                    CompilePattern{ "int main ( void ) { printf ( \"hello\" ) ; return 0 ; }" },
-                    PressButton{ PultAction::RunProgram },
+                .goal  = Goal::AllOf{{
+                    Goal::CompilePattern{ "int main ( void ) { printf ( \"hello\" ) ; return 0 ; }" },
+                    Goal::PressButton{ PultAction::RunProgram },
                 }},
                 .hint    = "Add printf, BUILD, then press RUN",
                 .details = R"(A program that does nothing is dull. Make it print.
@@ -267,7 +267,7 @@ the Program wall — and that's what finishes this step.)",
             {
                 .reset_carry  = false,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds  = {},
                     .plates = {
                         { .pos = { 0.0, World::get_FloorY<double>() + 1.2, -6.0 }, .tag = "" },
@@ -277,7 +277,7 @@ the Program wall — and that's what finishes this step.)",
                     },
                     .words  = {},
                 },
-                .goal    = ReachPlate{ "" },
+                .goal    = Goal::ReachPlate{ "" },
                 .hint    = "Try the editor pults, then jump onto the plate",
                 .details = R"(A few tools for managing the Editor wall:
 
@@ -308,7 +308,7 @@ Have a play, then jump onto the plate to continue.)",
             {
                 .reset_carry  = true,
                 .max_ai_words = 0,
-                .scene   = Scene{
+                .scene   = Scene::Data{
                     .ai_seeds = {},
                     .plates = {
                         { .pos = { 0.0, World::get_FloorY<double>() + 1.2, 0.0 }, .tag = "" },
@@ -318,7 +318,7 @@ Have a play, then jump onto the plate to continue.)",
                     },
                     .words  = {},
                 },
-                .goal    = ReachPlate{ "" },
+                .goal    = Goal::ReachPlate{ "" },
                 .hint    = "Jump onto the plate to begin \"Char Copy\"",
                 .details = R"(You're ready.
 
diff --git a/src/levels/level_check.cpp b/src/levels/level_check.cpp
deleted file mode 100644
index 5ee94a5..0000000
--- a/src/levels/level_check.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "level_check.hpp"
-#include <cctype>
-
-namespace LevelCheck {
-
-std::string
-normalize(const std::string& s)
-{
-    std::string out;
-    out.reserve(s.size());
-
-    bool last_space = true;   // treat start as if previous was space (trims leading)
-    for (char c : s) {
-        if (std::isspace(static_cast<unsigned char>(c))) {
-            if (!last_space) {
-                out += ' ';
-                last_space = true;
-            }
-        }
-        else {
-            out += c;
-            last_space = false;
-        }
-    }
-    // Trim trailing space if any
-    if (!out.empty() && out.back() == ' ')
-        out.pop_back();
-    return out;
-}
-
-bool
-contains_pattern(const std::string& haystack, const std::string& needle)
-{
-    if (needle.empty()) return true;
-    std::string norm_needle = normalize(needle);
-    return haystack.find(norm_needle) != std::string::npos;
-}
-
-}
diff --git a/src/levels/level_check.hpp b/src/levels/level_check.hpp
deleted file mode 100644
index 21d13b6..0000000
--- a/src/levels/level_check.hpp
+++ /dev/null
@@ -1,10 +0,0 @@
-#pragma once
-#include <string>
-
-namespace LevelCheck
-{
-    std::string
-         normalize(const std::string& s);
-
-    bool contains_pattern(const std::string& haystack, const std::string& needle);
-}
diff --git a/src/levels/scene.hpp b/src/levels/scene.hpp
index 8f74766..fc6f5be 100644
--- a/src/levels/scene.hpp
+++ b/src/levels/scene.hpp
@@ -5,47 +5,59 @@
 
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
-#include "utils/math.hpp"
 
 
-struct PlacedWord {
-    bool required = false;
-    Vec3 pos {};
+namespace Scene
+{
 
-    SDL_FColor  color    = ConfigColor::floor;
-    std::string text;
-};
+    namespace Placed
+    {
+    struct Word
+    {
+        bool required = false;
+        Vec3 pos {};
 
+        SDL_FColor  color = ConfigColor::floor;
+        std::string text;
+    };
 
-struct PlacedPlate {
-    Vec3 pos;
 
-    std::string tag;
-};
+    struct Plate
+    {
+        Vec3 pos;
 
+        std::string tag;
+    };
 
-struct PlacedPlatform {
-    Vec3 pos;
-    Vec3 half_extents { 1.0, 0.2, 1.0 };
 
-    SDL_FColor fill_color   { 0.45f, 0.45f, 0.65f, 1.0f };
-    SDL_FColor wire_color   { 0.70f, 0.70f, 0.90f, 1.0f };
-};
+    struct Platform
+    {
+        Vec3 pos;
+        Vec3 half_extents { 1.0, 0.2, 1.0 };
 
+        SDL_FColor fill_color { 0.45f, 0.45f, 0.65f, 1.0f };
+        SDL_FColor wire_color { 0.70f, 0.70f, 0.90f, 1.0f };
+    };
 
-struct PlacedAi {
-    double aggressiveness = 1.0;
-    Vec3   pos;
 
-    std::string text;
+    struct Ai
+    {
+        double aggressiveness = 1.0;
+        Vec3   pos;
 
-    Text3dAI::State initial_state = Text3dAI::State::Attack;
-};
+        std::string text;
+
+        Text3dAI::State initial_state = Text3dAI::State::Attack;
+    };
+    } // namespace Placed::
 
 
-struct Scene {
-    DynArray<PlacedAi>       ai_seeds {};
-    DynArray<PlacedPlate>    plates   {};
-    DynArray<PlacedPlatform> platforms{};
-    DynArray<PlacedWord>     words    {};
+struct Data
+{
+    DynArray<Placed::Ai>       ai_seeds {};
+    DynArray<Placed::Plate>    plates   {};
+    DynArray<Placed::Platform> platforms{};
+    DynArray<Placed::Word>     words    {};
 };
+
+} // namespace Scene
diff --git a/src/rendering/floor_mandelbrot.cpp b/src/rendering/floor_mandelbrot.cpp
index 5c05a2c..2001635 100644
--- a/src/rendering/floor_mandelbrot.cpp
+++ b/src/rendering/floor_mandelbrot.cpp
@@ -60,21 +60,21 @@ FloorMandelbrot::draw(GlRenderer& gl, const Camera& cam, const Light& light) con
 {
     if (_verts.empty()) return;
 
-    Mat4 view  = buildViewMat4(cam);
-    Mat4 proj  = gl.projection();
-    Mat4 model = Mat4::identity();
-    Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
+    Mat4 view  = buildViewMat4    (cam);
+    Mat4 proj  = gl.get_Projection();
+    Mat4 model = Mat4::identity   ();
+    Mat4 mvp   = Mat4::mul        (proj, Mat4::mul(view, model));
 
     gl.set_Wireframe(false);
-    gl.set_MVP(model, mvp);
+    gl.set_MVP      (model, mvp);
     gl.set_NormalMat(model);
-    gl.set_Light(light);
+    gl.set_Light    (light);
 
     gl.enable_MandelbrotMode(true);
-    gl.set_ColorUseVertex(false);
-    gl.draw_MeshColored(_verts.data(),
-                       static_cast<int>(_verts.size() / 9),
-                       _indices.data(),
-                       static_cast<int>(_indices.size()));
+    gl.set_ColorUseVertex   (false);
+    gl.draw_MeshColored     (_verts.data(),
+                             static_cast<int>(_verts.size() / 9),
+                             _indices.data(),
+                             static_cast<int>(_indices.size()));
     gl.enable_MandelbrotMode(false);
 }
diff --git a/src/rendering/floor_mandelbrot.hpp b/src/rendering/floor_mandelbrot.hpp
index 7c68419..6f5a269 100644
--- a/src/rendering/floor_mandelbrot.hpp
+++ b/src/rendering/floor_mandelbrot.hpp
@@ -5,14 +5,15 @@
 #include "rendering/gl_renderer.hpp"
 #include "utils/globals.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
+
 
 class Camera;
 
 
-class FloorMandelbrot {
-    DynArray<float> _verts;
+class FloorMandelbrot
+{
     DynArray<int>   _indices;
+    DynArray<float> _verts;
 public:
     void generate(float  world_scale,
                   float  floor_y,
diff --git a/src/rendering/gl_renderer.cpp b/src/rendering/gl_renderer.cpp
index fb9a861..88ce1be 100644
--- a/src/rendering/gl_renderer.cpp
+++ b/src/rendering/gl_renderer.cpp
@@ -432,10 +432,10 @@ bool GlRenderer::init(SDL_Window* window)
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Failed to initialize GLAD"); return false;
     }
 
-    GLuint vert = compileShader(GL_VERTEX_SHADER,   kVertSrc);
-    GLuint frag = compileShader(GL_FRAGMENT_SHADER, kFragSrc);
+    GLuint vert = compile_Shader(GL_VERTEX_SHADER,   kVertSrc);
+    GLuint frag = compile_Shader(GL_FRAGMENT_SHADER, kFragSrc);
     if (!vert || !frag)           return false;
-    if (!linkProgram(vert, frag)) return false;
+    if (!link_Program(vert, frag)) return false;
 
     glDeleteShader(vert);
     glDeleteShader(frag);
@@ -513,8 +513,8 @@ bool GlRenderer::init(SDL_Window* window)
     create_CompositeProgram_();
 
     {   // crosshair: reuse the blit vertex shader (vec2 aPos @ loc 0)
-        GLuint v = compileShader(GL_VERTEX_SHADER,   kBlitVertSrc);
-        GLuint f = compileShader(GL_FRAGMENT_SHADER, kCrosshairFragSrc);
+        GLuint v = compile_Shader(GL_VERTEX_SHADER,   kBlitVertSrc);
+        GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kCrosshairFragSrc);
         _crosshair_prog = glCreateProgram();
         glAttachShader(_crosshair_prog, v);
         glAttachShader(_crosshair_prog, f);
@@ -669,9 +669,9 @@ void GlRenderer::set_Light(const Light& light)
 {
     // Sun
     glUniform3f(_uLightDir,
-        (float)light.direction.x,
-        (float)light.direction.y,
-        (float)light.direction.z);
+        (float)light.sun_direction.x,
+        (float)light.sun_direction.y,
+        (float)light.sun_direction.z);
     glUniform3f(_uSunColor,
         (float)light.sun_color.x,
         (float)light.sun_color.y,
@@ -955,7 +955,7 @@ GlRenderer::draw_Emissive(const Camera& cam,
 // ─────────────────────────────────────────────────────────────────────────────
 // Shader helpers
 // ─────────────────────────────────────────────────────────────────────────────
-GLuint GlRenderer::compileShader(GLenum type, const char* src)
+GLuint GlRenderer::compile_Shader(GLenum type, const char* src)
 {
     GLuint s = glCreateShader(type);
     glShaderSource(s, 1, &src, nullptr);
@@ -969,7 +969,7 @@ GLuint GlRenderer::compileShader(GLenum type, const char* src)
     return s;
 }
 
-bool GlRenderer::linkProgram(GLuint vert, GLuint frag)
+bool GlRenderer::link_Program(GLuint vert, GLuint frag)
 {
     _prog = glCreateProgram();
     glAttachShader(_prog, vert); glAttachShader(_prog, frag);
@@ -983,13 +983,18 @@ bool GlRenderer::linkProgram(GLuint vert, GLuint frag)
     return true;
 }
 
-float GlRenderer::aspect() const { return _aspect; }
-const Mat4& GlRenderer::projection() const { return _proj; }
+float
+GlRenderer::get_Aspect() const { return _aspect; }
 
-void GlRenderer::enable_MandelbrotMode(bool on)
+const Mat4&
+GlRenderer::get_Projection() const { return _proj; }
+
+void
+GlRenderer::enable_MandelbrotMode(bool on)
 { glUniform1i(_uMandelbrot, on ? 1 : 0); }
 
-void GlRenderer::enable_WallPaperMode(bool on)
+void
+GlRenderer::enable_WallPaperMode(bool on)
 { glUniform1i(_uWallPaper, on ? 1 : 0); }
 
 
@@ -1018,8 +1023,8 @@ GlRenderer::create_FullscreenQuad_()
 void
 GlRenderer::create_BlitProgram_()
 {
-    GLuint v = compileShader(GL_VERTEX_SHADER,   kBlitVertSrc);
-    GLuint f = compileShader(GL_FRAGMENT_SHADER, kBlitFragSrc);
+    GLuint v = compile_Shader(GL_VERTEX_SHADER,   kBlitVertSrc);
+    GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kBlitFragSrc);
     _blit_prog = glCreateProgram();
     glAttachShader(_blit_prog, v);
     glAttachShader(_blit_prog, f);
@@ -1087,8 +1092,8 @@ GlRenderer::create_FBO_(int w, int h)
 void
 GlRenderer::create_ExtractProgram_()
 {
-    GLuint v = compileShader(GL_VERTEX_SHADER,   kBlitVertSrc);
-    GLuint f = compileShader(GL_FRAGMENT_SHADER, kExtractFragSrc);
+    GLuint v = compile_Shader(GL_VERTEX_SHADER,   kBlitVertSrc);
+    GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kExtractFragSrc);
     _extract_prog = glCreateProgram();
     glAttachShader(_extract_prog, v);
     glAttachShader(_extract_prog, f);
@@ -1100,8 +1105,8 @@ GlRenderer::create_ExtractProgram_()
 void
 GlRenderer::create_BlurProgram_()
 {
-    GLuint v = compileShader(GL_VERTEX_SHADER,   kBlitVertSrc);
-    GLuint f = compileShader(GL_FRAGMENT_SHADER, kBlurFragSrc);
+    GLuint v = compile_Shader(GL_VERTEX_SHADER,   kBlitVertSrc);
+    GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kBlurFragSrc);
     _blur_prog = glCreateProgram();
     glAttachShader(_blur_prog, v);
     glAttachShader(_blur_prog, f);
@@ -1227,8 +1232,8 @@ GlRenderer::run_BloomPipeline_()
 void
 GlRenderer::create_CompositeProgram_()
 {
-    GLuint v = compileShader(GL_VERTEX_SHADER,   kBlitVertSrc);
-    GLuint f = compileShader(GL_FRAGMENT_SHADER, kCompositeFragSrc);
+    GLuint v = compile_Shader(GL_VERTEX_SHADER,   kBlitVertSrc);
+    GLuint f = compile_Shader(GL_FRAGMENT_SHADER, kCompositeFragSrc);
     _composite_prog = glCreateProgram();
     glAttachShader(_composite_prog, v);
     glAttachShader(_composite_prog, f);
diff --git a/src/rendering/gl_renderer.hpp b/src/rendering/gl_renderer.hpp
index d45c782..b8e3e59 100644
--- a/src/rendering/gl_renderer.hpp
+++ b/src/rendering/gl_renderer.hpp
@@ -1,41 +1,40 @@
 #pragma once
 
-// ─────────────────────────────────────────────────────────────────────────────
-// GlRenderer
-//
-// Shader uniforms:
-//   u_MVP        mat4  — model-view-projection
-//   u_NormalMat  mat3  — transpose(inverse(MV))
-//   u_Color      vec3  — base object colour
-//   u_LightDir   vec3  — world-space light direction (normalised, toward light)
-//   u_Ambient    vec3  — RGB ambient floor colour
-//   u_Intensity  float — diffuse scale
-//   u_Wireframe  bool  — when true: skip lighting, output u_Color directly
-// ─────────────────────────────────────────────────────────────────────────────
-
 #include <SDL3/SDL.h>
 #include <glad/glad.h>
 
 #include "entities/camera.hpp"
 #include "utils/globals.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
 
-struct Mat4 {
+
+struct Mat4
+{
     float m[16]{};
     static Mat4 identity();
     static Mat4 perspective(float fovY_rad, float aspect, float near, float far);
     static Mat4 mul(const Mat4& a, const Mat4& b);
 };
 
-Mat4 buildViewMat4(const Camera& cam);
+Mat4 buildViewMat4 (const Camera& cam);
 Mat4 buildModelMat4(const Vec3& pos, float yaw);
 Mat4 buildModelMat4(const Vec3& pos, float yaw, float pitch);
 
 
-class GlRenderer {
-    int   _view_w{1}, _view_h{1};
-    float _aspect{1.0f};
+class GlRenderer
+{
+    bool  _crosshair_enabled {true};
+    int   _view_w         {1};
+    int   _view_h         {1};
+    int   _fbo_w          {0};
+    int   _fbo_h          {0};
+    int   _msaa_samples   {4};
+    int   _blur_w         {0};
+    int   _blur_h         {0};
+    float _bloom_strength { 0.6f };
+    float _aspect         {1.0f};
+
+
     Mat4  _proj;
     SDL_GLContext _ctx{};
     GLuint        _prog{};
@@ -66,144 +65,121 @@ class GlRenderer {
     GLint _uMandelbrot     {-1};
     GLint _uWallPaper      {-1};
     GLint _uTextLineSpacing{-1};
+    GLint _uUseVertexColor {-1};
 
-    GLuint _emissive_prog{},
-           _emissive_vao{},
-           _emissive_vbo{},
-           _emissive_ebo{};
+    GLuint _emissive_prog  {},
+           _emissive_vao   {},
+           _emissive_vbo   {},
+           _emissive_ebo   {};
 
-    GLint  _uEmissiveMVP    {-1};
+    GLint  _uEmissiveMVP   {-1};
 
-    GLuint _vao{}, _vbo{}, _ebo{};
-    GLuint _vao_c{},  _vbo_c{},  _ebo_c{};   // VAO/VBO/EBO for colored mesh
-    GLint  _uUseVertexColor{-1};
+    GLuint _vao{},   _vbo{},   _ebo{};
+    GLuint _vao_c{}, _vbo_c{}, _ebo_c{};   // VAO/VBO/EBO for colored mesh
 
     GLuint _line_vao{}, _line_vbo{};
     GLuint _menu_vao{}, _menu_vbo{};
 
 
-    // Scene FBO: where the main rendering pass writes.
-    GLuint _scene_fbo       {0};
-    GLuint _scene_color_tex {0};
-    GLuint _scene_depth_rbo {0};
-    GLuint _scene_fbo_ms       {0};
-    GLuint _scene_color_rbo_ms {0};
-    GLuint _scene_depth_rbo_ms {0};
-    int    _msaa_samples       {4};
-    int    _fbo_w           {0};
-    int    _fbo_h           {0};
+    GLuint _scene_fbo       {0},
+           _scene_color_tex {0},
+           _scene_depth_rbo {0},
+           _scene_fbo_ms       {0},
+           _scene_color_rbo_ms {0},
+           _scene_depth_rbo_ms {0};
 
-    // Fullscreen-quad geometry for compositing passes.
-    GLuint _fullscreen_vao  {0};
-    GLuint _fullscreen_vbo  {0};
+    GLuint _fullscreen_vao  {0},
+           _fullscreen_vbo  {0};
 
-    // Blit program: samples scene texture, writes to screen unchanged.
     GLuint _blit_prog       {0};
     GLint  _uBlitTex        {-1};
 
-        // Half-resolution FBOs for the blur ping-pong.
-    GLuint _bright_fbo      {0};
-    GLuint _bright_tex      {0};
-    GLuint _blur_fbo[2]     {0, 0};
-    GLuint _blur_tex[2]     {0, 0};
-    int    _blur_w          {0};
-    int    _blur_h          {0};
-
-    // Crosshair: tiny screen-space overlay, inverts the pixels behind it.
-    GLuint _crosshair_prog {0};
-    GLuint _crosshair_vao  {0};
-    GLuint _crosshair_vbo  {0};
-    bool   _crosshair_enabled {true};
-
-    // Programs
-    GLuint _extract_prog    {0};
-    GLuint _blur_prog       {0};
-    GLuint _composite_prog  {0};
-
-    // Uniforms
+    GLuint _bright_fbo      {0},
+           _bright_tex      {0};
+    GLuint _blur_fbo[2]     {0, 0},
+           _blur_tex[2]     {0, 0};
+
+    GLuint _crosshair_prog {0},
+           _crosshair_vao  {0},
+           _crosshair_vbo  {0};
+
+    GLuint _extract_prog    {0},
+           _blur_prog       {0},
+           _composite_prog  {0};
+
     GLint  _uExtractTex     {-1};
     GLint  _uBlurTex        {-1};
-    GLint  _uBlurDir        {-1};       // (1,0) or (0,1)
-    GLint  _uBlurTexelSize  {-1};       // (1/w, 1/h)
-    GLint  _uComposeScene   {-1};
-    GLint  _uComposeBloom   {-1};
-    GLint  _uComposeStrength{-1};       // how much bloom to add (default 1.0)
-    float  _bloom_strength { 0.6f };
-
-    // Emissive uniforms on the main program
+    GLint  _uBlurDir        {-1};
+    GLint  _uBlurTexelSize  {-1};
+    GLint  _uComposeScene   {-1},
+           _uComposeBloom   {-1},
+           _uComposeStrength{-1};
+
     GLint  _uEmissiveColor    {-1};
     GLint  _uEmissiveStrength {-1};
 
-    void create_FBO_(int w, int h);
-    void resize_FBO_(int w, int h);
-    void destroy_FBO_();
-    void create_FullscreenQuad_();
-    void create_BlitProgram_();
-    void create_BloomFBOs_(int scene_w, int scene_h);
-    void resize_BloomFBOs_(int scene_w, int scene_h);
-    void destroy_BloomFBOs_();
-    void create_ExtractProgram_();
-    void create_BlurProgram_();
+    void create_FBO_             (int w, int h);
+    void resize_FBO_             (int w, int h);
+    void destroy_FBO_            ();
+    void create_FullscreenQuad_  ();
+    void create_BlitProgram_     ();
+    void create_BloomFBOs_       (int scene_w, int scene_h);
+    void resize_BloomFBOs_       (int scene_w, int scene_h);
+    void destroy_BloomFBOs_      ();
+    void create_ExtractProgram_  ();
+    void create_BlurProgram_     ();
     void create_CompositeProgram_();
-    void run_BloomPipeline_();
+    void run_BloomPipeline_      ();
 
     void draw_Crosshair_();
 
-    GLuint compileShader(GLenum type, const char* src);
-    bool   linkProgram(GLuint vert, GLuint frag);
+    GLuint compile_Shader(GLenum type, const char* src);
+    bool   link_Program  (GLuint vert, GLuint frag);
 public:
-    bool init(SDL_Window* window);
-    void begin_Frame(int viewport_w, int viewport_h);
-    void end_Frame(SDL_Window* window);
-    void clear_Depth();
-
-    void set_MVP       (const Mat4& model, const Mat4& mvp);
-    void set_NormalMat (const Mat4& model);
-    void set_Color     (float  r, float  g, float  b);
-    void set_FaceShade (float r, float g, float b,
+    static void free_MeshBuffers(unsigned int vbo, unsigned int ebo);
+
+    bool init           (SDL_Window* window);
+    void begin_Frame    (int viewport_w, int viewport_h);
+    void end_Frame      (SDL_Window* window);
+    void clear_Depth    ();
+
+    void set_MVP        (const Mat4& model, const Mat4& mvp);
+    void set_NormalMat  (const Mat4& model);
+    void set_Color      (float  r, float  g, float  b);
+    void set_FaceShade  (float r, float g, float b,
                         float back_dim, bool use_front);
-    void set_Light     (const Light& light);
-    void set_Wireframe (bool on);
+    void set_Light      (const Light& light);
+    void set_Wireframe  (bool on);
+    void set_Emissive   (float r, float g, float b, float strength);
+    void set_Crosshair  (bool on) { _crosshair_enabled = on; }
+    void set_DepthTest  (bool on);
+    void set_CullBack   (bool on);
     void set_ColorUseVertex (bool on);
     void set_TextLineSpacing(float m);
-    void set_Emissive  (float r, float g, float b, float strength);
     void set_BloomStrength  (float s) { _bloom_strength = s; }
-    void set_Crosshair(bool on) { _crosshair_enabled = on; }
-    void set_DepthTest(bool on);
-    void set_CullBack (bool on);
 
     void enable_MandelbrotMode(bool on);
     void enable_WallPaperMode (bool on);
 
-    float       fov_y()      const { return SDL_PI_F / 3.0f; }
-    float       aspect()     const;
-    const Mat4& projection() const;
+    float       get_Fov_y     () const { return SDL_PI_F / 3.0f; }
+    float       get_Aspect    () const;
+    const Mat4& get_Projection() const;
+    GLuint      get_Program   () const { return _prog; }
 
-    // ── Draw calls ───────────────────────────────────────────────────────────
-    // Indexed triangle mesh: verts = interleaved [pos(3f) | normal(3f)]
-    void draw_Mesh(const float* verts,   int vert_count,
-                   const int*   indices, int index_count);
+    void draw_Mesh       (const float* verts,   int vert_count,
+                          const int*   indices, int index_count);
     void draw_MeshColored(const float* verts,   int vert_count,
                           const int*   indices, int index_count);
-    void draw_MeshCached(unsigned int& vbo, unsigned int& ebo, int& index_count,
-                         bool dirty,
-                         const float* verts, int vert_count,
-                         const int* indices, int idx_count);
-    static void free_MeshBuffers(unsigned int vbo, unsigned int ebo);
-
-    // Line pairs: flat [x,y,z, x,y,z, ...]
-    void draw_Lines(const float* points, int point_count);
-
-    // Solid lit box centred at origin (in model space) with given half-extents.
-    // Call set_MVP / set_NormalMat / set_Color / set_Light before this.
-    void draw_Box(float hx, float hy, float hz);
-
-    void draw_Menu();
-
-    void draw_Emissive(const Camera& cam,
-                       const float* verts,   int vert_count,
-                       const int*   indices, int index_count,
-                       float r, float g, float b, float strength);
-
-    GLuint program() const { return _prog; }
+    void draw_MeshCached (unsigned int& vbo, unsigned int& ebo, int& index_count,
+                          bool dirty,
+                          const float* verts, int vert_count,
+                          const int* indices, int idx_count);
+
+    void draw_Lines      (const float* points, int point_count);
+    void draw_Box        (float hx, float hy, float hz);
+    void draw_Menu       ();
+    void draw_Emissive   (const Camera& cam,
+                          const float* verts,   int vert_count,
+                          const int*   indices, int index_count,
+                          float r, float g, float b, float strength);
 };
diff --git a/src/states/game_context.cpp b/src/states/game_context.cpp
index 0d064ec..5b408a2 100644
--- a/src/states/game_context.cpp
+++ b/src/states/game_context.cpp
@@ -1,8 +1,7 @@
-#include "states/game_context.hpp"
-
 #include <algorithm>
 
 #include "text_3d/text_3d.hpp"
+#include "states/game_context.hpp"
 
 
 void
@@ -21,7 +20,7 @@ GameContext::clear_WallRole(Wall::Role role)
 {
     wall_texts.erase(
         std::remove_if(wall_texts.begin(), wall_texts.end(),
-            [role](const TextWallPtr& wt){ return wt->role == role; }),
+            [role](const Wall::Ptr& wt){ return wt->role == role; }),
         wall_texts.end());
 }
 
@@ -29,8 +28,8 @@ GameContext::clear_WallRole(Wall::Role role)
 void
 GameContext::add_WallText(Wall::Position pos, Wall::Role role, Text3dPtr t)
 {
-    wall_texts.push_back(cpputils::make_unique<TextWall>(
-        TextWall{ pos, role, std::move(t) }));
+    wall_texts.push_back(cpputils::make_unique<Wall::Text>(
+        Wall::Text{ pos, role, std::move(t) }));
 }
 
 
diff --git a/src/states/game_context.hpp b/src/states/game_context.hpp
index d42b88b..4962355 100644
--- a/src/states/game_context.hpp
+++ b/src/states/game_context.hpp
@@ -1,20 +1,20 @@
 #pragma once
 
-#include <memory>
 #include <string>
 
 #include "entities/game_object.hpp"
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
 #include "wall/wall.hpp"
 
-class  Player;
+
 class  Camera;
+class  Player;
 class  World;
 struct Light;
 struct PultButton;
 
+
 struct GameContext
 {
     cpputils::unique_ptr<Player> player;
@@ -25,7 +25,7 @@ struct GameContext
     DynArray<Text3dPtr>     words;
     DynArray<GameObjectPtr> scenery;
     DynArray<PultButton*>   buttons;
-    TextWallList            wall_texts;
+    Wall::PtrList           wall_texts;
 
     void drop_WordToFloor(Text3dPtr word, const Vec3& vel);
     void clear_WallRole  (Wall::Role role);
diff --git a/src/states/game_state.cpp b/src/states/game_state.cpp
index 8612639..b8b00a4 100644
--- a/src/states/game_state.cpp
+++ b/src/states/game_state.cpp
@@ -7,7 +7,6 @@
 #include "entities/solid_box.hpp"
 #include "entities/world.hpp"
 #include "game_state.hpp"
-#include "levels/level_check.hpp"
 #include "rendering/gl_renderer.hpp"
 #include "systems/aim.hpp"
 #include "systems/celebration_system.hpp"
@@ -19,9 +18,8 @@
 #include "text_3d/text_label.hpp"
 #include "utils/config.hpp"
 #include "utils/frame_profiler.hpp"
-#include "utils/text_wrap.hpp"
-#include "wall/text_wall.hpp"
-#include "wall/text_wall_scroll.hpp"
+#include "utils/text.hpp"
+#include "wall/wall.hpp"
 
 
 
@@ -49,38 +47,39 @@ GameState::GameState(size_t starting_level)
     _ctx.camera = cpputils::make_unique<Camera>();
     _ctx.light  = cpputils::make_unique<Light> ();
 
-    _input_sys       = cpputils::make_unique<InputSystem>      ();
-    _physics_sys     = cpputils::make_unique<PhysicsSystem>    ();
-    _projectiles_sys = cpputils::make_unique<ProjectileSystem> ();
-    _compiler_sys    = cpputils::make_unique<CompilerSystem>   ();
-    _program_sys     = cpputils::make_unique<ProgramSystem>    ();
-    _word_anim_sys   = cpputils::make_unique<WordAnimSystem>   ();
-    _freelook_sys    = cpputils::make_unique<FreelookSystem>   ();
-    _particle_sys    = cpputils::make_unique<ParticleSystem>   ();
-    _dyn_loader_sys  = cpputils::make_unique<DynLoaderSystem>  ();
-    _celebration_sys = cpputils::make_unique<CelebrationSystem>();
+    _input_sys       = cpputils::make_unique<InputSystem>       ();
+    _physics_sys     = cpputils::make_unique<PhysicsSystem>     ();
+    _projectiles_sys = cpputils::make_unique<ProjectileSystem>  ();
+    _compiler_sys    = cpputils::make_unique<CompilerSystem>    ();
+    _program_sys     = cpputils::make_unique<ProgramSystem>     ();
+    _word_anim_sys   = cpputils::make_unique<WordAnimSystem>    ();
+    _freelook_sys    = cpputils::make_unique<FreelookSystem>    ();
+    _particle_sys    = cpputils::make_unique<ParticleSystem>    ();
+    _dyn_loader_sys  = cpputils::make_unique<DynLoaderSystem>   ();
+    _celebration_sys = cpputils::make_unique<CelebrationSystem> ();
+    _highlight_sys   = cpputils::make_unique<CppHighlightSystem>();
 
     _floor_sys       = cpputils::make_unique<FloorMandelbrot>  ();
     _floor_sys->generate(World::get_BoxScale(), World::get_FloorY());
 
-    _wall_labels     = WallLabel::generate_All(World::get_BoxScale());
+    _wall_labels     = Wall::Label::generate_All(World::get_BoxScale());
 
     _word_ai_sys     = cpputils::make_unique<WordAiSystem>();
 
     _pult_sys        = cpputils::make_unique<PultSystem>  ();
     _pult_sys->init(_ctx.scenery, _ctx.buttons, World::get_BoxScale());
 
-    if (starting_level >= Level::level_Count()) starting_level = 0;
-    _level_director  = cpputils::make_unique<LevelDirector>(Level::get_Level(starting_level));
+    if (starting_level >= Level::get_Count()) starting_level = 0;
+    _level_director  = cpputils::make_unique<LevelDirector>(Level::get_Data(starting_level));
 
     _level_director->enter_Step(_ctx);
     _word_ai_sys->set_MaxActiveAi(_level_director->get_MaxAiForStep());
 
     _hint_sys = cpputils::make_unique<HintSystem>();
-    if (!_level_director->complete())
-        _hint_sys->set_Hint(_level_director->current_hint());
+    if (!_level_director->is_LevelComplete())
+        _hint_sys->set_Hint(_level_director->get_CurrentHint());
 
-    if (_level_director->runner().dynamic_lib())
+    if (_level_director->get_Runner().is_DynamicLib())
         sandbox_LoadFileToWall();
 
     /*
@@ -133,11 +132,11 @@ GameState::carriedline_Update()
 
     if (fs.active) return;
 
-    const Vec3   anchor    = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST);
+    const Vec3   anchor    = CarryMath::get_LineAnchor(*_ctx.camera, CarryMath::CARRY_DIST);
     const Vec3   right     = _ctx.camera->right;
     const double glyph_yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z);
 
-    DynArray<Vec3> slots = CarryMath::slot_Positions(_carried, anchor, right, CarryMath::CARRY_GAP);
+    DynArray<Vec3> slots = CarryMath::get_SlotPosition(_carried, anchor, right, CarryMath::CARRY_GAP);
     DynArray<CarriedWordNode*> nodes = _carried.reverse_nodes();
 
     // Easing back from the frozen spots: lerp each word from its release
@@ -174,13 +173,13 @@ GameState::pult_DispatchAction(PultAction act)
     switch (act) {
         case PultAction::Compile:          on_Compile();               break;
         case PultAction::RunProgram:       on_Run();                   break;
-        case PultAction::ScrollEditorUp:   TextWallScroll::scroll_Up(_ctx.wall_texts, Wall::Role::Editor);
+        case PultAction::ScrollEditorUp:   Wall::Text::scroll_Up(_ctx.wall_texts, Wall::Role::Editor);
                                            _editor_wall.scroll(ConfigWall::scroll_step);
                                                                        break;
-        case PultAction::ScrollEditorDown: TextWallScroll::scroll_Down(_ctx.wall_texts, Wall::Role::Editor);
+        case PultAction::ScrollEditorDown: Wall::Text::scroll_Down(_ctx.wall_texts, Wall::Role::Editor);
                                            _editor_wall.scroll(-ConfigWall::scroll_step);
                                                                        break;
-        case PultAction::ClearEditor:      TextWallScroll::clear_ToFloor(_ctx.wall_texts, _ctx.words, Wall::Role::Editor);
+        case PultAction::ClearEditor:      Wall::Text::clear_ToFloor(_ctx.wall_texts, _ctx.words, Wall::Role::Editor);
                                            _editor_wall.clear();
                                                                        break;
         case PultAction::ConnectEditor:    wallconnect_BeginEditor();  break;
@@ -218,7 +217,7 @@ GameState::on_Pick()
         if (base->type == ObjectType::Text) {
             _level_director->record_PickedUp(base->text);
             base->set_Look(ConfigColor::keep, Text3d::depth_floor);
-            TextWall::show_TokenInfo(_ctx.wall_texts, base->text);
+            Wall::Text::show_TokenInfo(_ctx.wall_texts, base->text);
         }
         carry_BeginAnim(std::move(base), true);
         return true;
@@ -231,7 +230,7 @@ GameState::on_Pick()
 
         _level_director->record_PickedUp(word->text);
         word->set_Look(ConfigColor::keep, Text3d::depth_floor);
-        TextWall::show_TokenInfo(_ctx.wall_texts, word->text);
+        Wall::Text::show_TokenInfo(_ctx.wall_texts, word->text);
 
         carry_BeginAnim(std::move(word), false);
         return true;
@@ -258,7 +257,7 @@ GameState::on_DropLast()
     _anims_drop.push_back(std::move(drop));
 
     if (!_carried.empty())
-        TextWall::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
+        Wall::Text::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
     else
         _level_director->show_Details(_ctx);
 
@@ -288,7 +287,7 @@ GameState::on_ShootOne()
                              _ctx.camera->fwd, _ctx.camera->pos, aim);
 
     if (!_carried.empty() && _carried.last && _carried.last->word)
-        TextWall::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
+        Wall::Text::show_TokenInfo(_ctx.wall_texts, _carried.last->word->text);
     else _level_director->show_Details(_ctx);
 
     _level_director->record_Shot();
@@ -325,10 +324,10 @@ GameState::on_ShootAll()
 
 
 void GameState::on_Compile() {
-    std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
+    std::string src = Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
 
-    if ( !_level_director->complete() &&
-          _level_director->runner().dynamic_lib()) {
+    if ( !_level_director->is_LevelComplete() &&
+          _level_director->get_Runner().is_DynamicLib()) {
         const std::string path = sandbox_CanonicalPath();
         std::string stripped;
         for (char c : src) if (!std::isspace((unsigned char)c))
@@ -354,8 +353,8 @@ GameState::on_Run()
 void
 GameState::on_DebugPrint()
 {
-    std::print("TEXT::: {0}\n", TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Program));
-    for (TextWallPtr& wt : _ctx.wall_texts)
+    std::print("TEXT::: {0}\n", Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Program));
+    for (Wall::Ptr& wt : _ctx.wall_texts)
         if (wt->text3d->type == ObjectType::Text)
             SDL_Log("wall text '%s' y=%.3f", wt->text3d->text.c_str(), wt->text3d->pos.y);
 }
@@ -469,7 +468,7 @@ GameState::projectile_LandOnFloor(ProjectileResult& result)
 void
 GameState::projectile_LandOnWall(ProjectileResult& result)
 {
-    DynArray<TextWallPtr> placed;
+    DynArray<Wall::Ptr> placed;
     DynArray<Text3d*>     editor_group;
     placed.reserve(result.words.size());
 
@@ -481,7 +480,7 @@ GameState::projectile_LandOnWall(ProjectileResult& result)
         w->body.mode = PhysicsMode::Static;
         w->body.vel  = Vec3{0, 0, 0};
 
-        TextWallPtr wt = TextWall::from_Drop(std::move(w));
+        Wall::Ptr wt = Wall::Text::from_Drop(std::move(w));
         if (wt && wt->text3d && wt->role == Wall::Role::Editor)
             editor_group.push_back(wt->text3d.get());
         placed.push_back(std::move(wt));
@@ -496,7 +495,7 @@ GameState::projectile_LandOnWall(ProjectileResult& result)
         _editor_wall.on_LinePlaced(editor_group, impact);
     }
 
-    for (TextWallPtr& wt : placed)
+    for (Wall::Ptr& wt : placed)
         _ctx.wall_texts.push_back(std::move(wt));
 
     if (!editor_group.empty())
@@ -508,11 +507,11 @@ void
 GameState::projectile_LandOnWallText(ProjectileResult& result,
                                       DynArray<size_t>& wall_text_to_erase)
 {
-    if (EditorWall::is_LineNumberHit(result.wall_text_index)) {
-        const size_t lid   = EditorWall::line_Of(result.wall_text_index);
+    if (Wall::Editor::is_LineNumberHit(result.wall_text_index)) {
+        const size_t lid   = Wall::Editor::line_Of(result.wall_text_index);
         const double delta = _editor_wall.scroll_DeltaToEye(lid, _ctx.camera->pos.y);
 
-        for (TextWallPtr& wt : _ctx.wall_texts)
+        for (Wall::Ptr& wt : _ctx.wall_texts)
             if (wt && wt->text3d && wt->role == Wall::Role::Editor)
                 wt->text3d->pos.y += delta;
         _editor_wall.scroll(delta);
@@ -533,7 +532,7 @@ GameState::walltext_HandleShootDown(ProjectileResult& result,
 {
     bool removed_editor = false;
     if (result.wall_text_index < _ctx.wall_texts.size()) {
-        TextWallPtr& wt = _ctx.wall_texts[result.wall_text_index];
+        Wall::Ptr& wt = _ctx.wall_texts[result.wall_text_index];
         if (wt && wt->text3d) {
             removed_editor = (wt->role == Wall::Role::Editor);
             _editor_wall.on_WordRemoved(wt->text3d.get());
@@ -586,26 +585,26 @@ GameState::handle_Input(FrameInput& input, double dt) {
         }
     }
 
-    if (_wall_connection.target() == WallConnection::Target::Editor) {
+    if (_wall_connection.get_Target() == WallConnection::Target::Editor) {
         WallConnection::Request req = _wall_connection.feed_Vim(input.vim_keys, _ctx.camera->pos.y);
         input.vim_keys.clear();
         switch (req) {
             case WallConnection::Request::Write:
-                editor_CommitToWall(_wall_connection.lines(), false);
+                editor_CommitToWall(_wall_connection.get_Lines(), false);
                 _wall_connection.mark_Saved();
                 break;
             case WallConnection::Request::WriteQuit:
-                editor_CommitToWall(_wall_connection.lines(), true);
+                editor_CommitToWall(_wall_connection.get_Lines(), true);
                 _wall_connection.end();
                 _frame_input.capture_vim = false;
                 break;
             case WallConnection::Request::Exit:
-                editor_CommitToWall(_wall_connection.lines(), true);
+                editor_CommitToWall(_wall_connection.get_Lines(), true);
                 _wall_connection.end();
                 _frame_input.capture_vim = false;
                 break;
             case WallConnection::Request::QuitDiscard:
-                editor_CommitToWall(_wall_connection.lines(), true);
+                editor_CommitToWall(_wall_connection.get_Lines(), true);
                 _wall_connection.end();
                 _frame_input.capture_vim = false;
                 break;
@@ -613,7 +612,7 @@ GameState::handle_Input(FrameInput& input, double dt) {
                 break;
         }
     }
-    else if (_wall_connection.target() == WallConnection::Target::Program) {
+    else if (_wall_connection.get_Target() == WallConnection::Target::Program) {
         _wall_connection.set_ProgramBuffer(input.typing_buffer);
     }
     else if (input.typing_mode) {
@@ -638,7 +637,7 @@ GameState::update_PlayerCamera(FrameInput& input, double dt)
 
     _freelook_sys->update(dt);
     _ctx.player->compute_Movement(input);
-    _ctx.camera->syncFromPlayer(*_ctx.player);
+    _ctx.camera->sync_FromPlayer(*_ctx.player);
 }
 
 void
@@ -660,12 +659,12 @@ GameState::update(double dt, const GlRenderer* gl)
 
     { FP_ZONE("update.post_step");
 
-        for (TextWallPtr& wt : _ctx.wall_texts) {
+        for (Wall::Ptr& wt : _ctx.wall_texts) {
             if (!wt || !wt->text3d) continue;
-            wt->text3d->pitch = Wall::tilt_TowardEye(wt->text3d->pos, _ctx.camera->pos);
+            wt->text3d->pitch = Wall::Text::tilt_TowardEye(wt->text3d->pos, _ctx.camera->pos);
         }
 
-        for (WallLabel& lbl : _wall_labels)
+        for (Wall::Label& lbl : _wall_labels)
             lbl.update(dt, *_ctx.camera);
 
         carriedline_Update();
@@ -673,10 +672,10 @@ GameState::update(double dt, const GlRenderer* gl)
         _word_anim_sys->update(_anims_add, _anims_drop, _carried, _ctx.words, dt);
 
         _pult_sys->  update(dt, *_ctx.camera);
-        _plate_sys-> update(dt, *_ctx.player, _level_director->step_Plates());
+        _plate_sys-> update(dt, *_ctx.player, _level_director->get_StepPlates());
         _editor_wall.update(dt, _ctx.camera->pos);
 
-        _wall_connection.update(dt, *_ctx.camera, gl->aspect(), gl->fov_y());
+        _wall_connection.update(dt, *_ctx.camera, gl->get_Aspect(), gl->get_Fov_y());
     }
 
 
@@ -715,7 +714,7 @@ GameState::update(double dt, const GlRenderer* gl)
     { FP_ZONE("update.highlight");
         DynArray<HiSpan> spans;
         uint64_t gen;
-        if (_highlight_sys.poll(spans, gen) && gen == _editor_gen)
+        if (_highlight_sys->poll(spans, gen) && gen == _editor_gen)
             _editor_file.apply_Spans(spans);
     }
 
@@ -761,14 +760,14 @@ GameState::render(SDL_Window& window, GlRenderer& renderer)
     }
 
     { FP_ZONE("render.wall_texts");
-        for (const TextWallPtr& wt : _ctx.wall_texts) {
+        for (const Wall::Ptr& wt : _ctx.wall_texts) {
             if (_editor_hidden && wt && wt->role == Wall::Role::Editor) continue;
             wt->draw(renderer, *_ctx.camera, *_ctx.light);
         }
     }
 
     { FP_ZONE("render.wall_labels");
-        for (const WallLabel& lbl : _wall_labels)
+        for (const Wall::Label& lbl : _wall_labels)
             lbl.draw(renderer, *_ctx.camera, *_ctx.light);
     }
 
@@ -866,7 +865,7 @@ GameState::update_WorldSimulation(double dt)
             lbl->update(dt, *_ctx.camera);
 
         all_labels.push_back(&_hint_sys->get_Label());
-        for (WallLabel& wl : _wall_labels)
+        for (Wall::Label& wl : _wall_labels)
             all_labels.push_back(&wl.label);
     }
 
@@ -878,30 +877,30 @@ GameState::update_WorldSimulation(double dt)
     { FP_ZONE("updateworldsim.build_wall_hits");
         wall_text_hits.reserve(_ctx.wall_texts.size());
         for (size_t i = 0; i < _ctx.wall_texts.size(); ++i) {
-            const TextWallPtr& wt = _ctx.wall_texts[i];
+            const Wall::Ptr& wt = _ctx.wall_texts[i];
             if (!wt || !wt->text3d) continue;
             wall_text_hits.push_back({
                     wt->wall_position,
                     i,
-                    wt->text3d->aabb_min(),
-                    wt->text3d->aabb_max(),
+                    wt->text3d->aabb_Min(),
+                    wt->text3d->aabb_Max(),
                 });
         }
 
-        for (const EditorWall::NumberHit& nh : _editor_wall.number_Hitboxes())
+        for (const Wall::Editor::NumberHit& nh : _editor_wall.number_Hitboxes())
             wall_text_hits.push_back({ Wall::Position::NegX, nh.index,
-                                       nh.aabb_min, nh.aabb_max });
+                                       nh.aabb_Min, nh.aabb_Max });
 
         for (size_t li = 0; li < _wall_labels.size(); ++li) {
-            const DynArray<Text3dPtr>& words = _wall_labels[li].label.words();
+            const DynArray<Text3dPtr>& words = _wall_labels[li].label.get_Words();
             for (size_t wi = 0; wi < words.size(); ++wi) {
                 if (!words[wi]) continue;
                 constexpr size_t LABEL_HIT_BASE = size_t(1) << 48;
                 wall_text_hits.push_back({
-                        Wall::position_of(_wall_labels[li].role),
+                        Wall::position_Of(_wall_labels[li].role),
                         LABEL_HIT_BASE | (li << 16) | wi,
-                        words[wi]->aabb_min(),
-                        words[wi]->aabb_max(),
+                        words[wi]->aabb_Min(),
+                        words[wi]->aabb_Max(),
                         });
             }
         }
@@ -986,7 +985,7 @@ GameState::level_TryAdvance(double dt)
     if (res.advanced) {
         _level_director->enter_Step(_ctx);
         _word_ai_sys->set_MaxActiveAi(_level_director->get_MaxAiForStep());
-        _hint_sys->set_Hint(_level_director->current_hint());
+        _hint_sys->set_Hint(_level_director->get_CurrentHint());
     } else {
         _hint_sys->clear();
         _level_director->show_Details(_ctx);
@@ -1045,7 +1044,7 @@ GameState::dyn_Apply(const DynArray<DynObject>& objs)
 
 std::string
 GameState::sandbox_CanonicalPath() const {
-    return _level_director ? _level_director->runner().source_file() : std::string{};
+    return _level_director ? _level_director->get_Runner().get_SourceFile() : std::string{};
 }
 
 std::string
@@ -1081,7 +1080,7 @@ GameState::sandbox_LoadFileToWall()
 
 void
 GameState::sandbox_Restore() {
-    if (!_level_director || !_level_director->runner().dynamic_lib()) return;
+    if (!_level_director || !_level_director->get_Runner().is_DynamicLib()) return;
     if (SourceTokens::copy_File(sandbox_BackupPath(), sandbox_CanonicalPath()))
         sandbox_LoadFileToWall();
 }
@@ -1092,7 +1091,7 @@ GameState::typing_RebuildPreview(const std::string& s)
 {
     typing_ClearPreview();
 
-    const Vec3   anchor    = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST);
+    const Vec3   anchor    = CarryMath::get_LineAnchor(*_ctx.camera, CarryMath::CARRY_DIST);
     const double glyph_yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z);
 
     std::istringstream in(s);
@@ -1135,7 +1134,7 @@ GameState::carry_BeginAnim(Text3dPtr word, bool with_pitch)
     anim.t           = 0.0;
     anim.complete    = false;
 
-    const Vec3   anchor    = CarryMath::line_Anchor(*_ctx.camera, CarryMath::CARRY_DIST);
+    const Vec3   anchor    = CarryMath::get_LineAnchor(*_ctx.camera, CarryMath::CARRY_DIST);
     const double glyph_yaw = SDL_atan2(-_ctx.camera->fwd.x, -_ctx.camera->fwd.z);
     anim.target_pos = anchor;
     anim.yaw_target = static_cast<float>(glyph_yaw);
@@ -1211,7 +1210,7 @@ GameState::editor_Clear()
 DynArray<std::string>
 GameState::editor_AbsorbLines()
 {
-    std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
+    std::string src = Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
     DynArray<std::string> lines;
 
     std::string cur;
@@ -1229,7 +1228,7 @@ GameState::editor_AbsorbLines()
 DynArray<std::string>
 GameState::editor_ReadLines() const
 {
-    std::string src = TextWall::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
+    std::string src = Wall::Text::extract_Text(_ctx.wall_texts, Wall::Role::Editor);
     DynArray<std::string> lines;
     std::string cur;
     for (char ch : src) {
@@ -1336,12 +1335,12 @@ GameState::editor_SyncFile()
 {
     _editor_file.clear();
     for (const DynArray<Text3d*>& line : _editor_wall.lines_InOrder()) {
-        TextFile::Line fl;
+        Text::Line fl;
         for (Text3d* w : line)
-            if (w) fl.tokens.push_back(TextFile::Token{ w->text, 0, 0, w });
+            if (w) fl.tokens.push_back(Text::Token{ w->text, 0, 0, w });
         _editor_file.lines.push_back(std::move(fl));
     }
 
     ++_editor_gen;
-    _highlight_sys.request(_editor_file.render_Source(), _editor_gen);
+    _highlight_sys->request(_editor_file.render_Source(), _editor_gen);
 }
diff --git a/src/states/game_state.hpp b/src/states/game_state.hpp
index 8d6a19e..096c5e0 100644
--- a/src/states/game_state.hpp
+++ b/src/states/game_state.hpp
@@ -1,7 +1,5 @@
 #pragma once
 
-#include <memory>
-
 #include "cpputils/unique_ptr.hpp"
 #include "entities/plate.hpp"
 #include "istate.hpp"
@@ -27,49 +25,48 @@
 #include "systems/wall_connection.hpp"
 #include "systems/word_ai_system.hpp"
 #include "systems/word_anim.hpp"
-#include "text_3d/text_file.hpp"
 #include "text_3d/vim_buffer.hpp"
 #include "utils/carry_math.hpp"
 #include "utils/globals.hpp"
-#include "wall/editor_wall.hpp"
-#include "wall/text_wall.hpp"
-#include "wall/wall_label.hpp"
+#include "utils/text.hpp"
+#include "wall/editor.hpp"
+#include "wall/wall.hpp"
 
 
 class GameState : public IState
 {
 
-    cpputils::unique_ptr<CelebrationSystem>_celebration_sys;
-    cpputils::unique_ptr<CompilerSystem>   _compiler_sys;
-    cpputils::unique_ptr<DynLoaderSystem>  _dyn_loader_sys;
-    cpputils::unique_ptr<FloorMandelbrot>  _floor_sys;
-    cpputils::unique_ptr<FreelookSystem>   _freelook_sys;
-    cpputils::unique_ptr<HintSystem>       _hint_sys;
-    cpputils::unique_ptr<InputSystem>      _input_sys;
-    cpputils::unique_ptr<LevelDirector>    _level_director;
-    cpputils::unique_ptr<ParticleSystem>   _particle_sys;
-    cpputils::unique_ptr<PhysicsSystem>    _physics_sys;
-    cpputils::unique_ptr<PlateSystem>      _plate_sys;
-    cpputils::unique_ptr<ProgramSystem>    _program_sys;
-    cpputils::unique_ptr<ProjectileSystem> _projectiles_sys;
-    cpputils::unique_ptr<PultSystem>       _pult_sys;
-    cpputils::unique_ptr<WordAiSystem>     _word_ai_sys;
-    cpputils::unique_ptr<WordAnimSystem>   _word_anim_sys;
+    cpputils::unique_ptr<CelebrationSystem>  _celebration_sys;
+    cpputils::unique_ptr<CompilerSystem>     _compiler_sys;
+    cpputils::unique_ptr<CppHighlightSystem> _highlight_sys;
+    cpputils::unique_ptr<DynLoaderSystem>    _dyn_loader_sys;
+    cpputils::unique_ptr<FloorMandelbrot>    _floor_sys;
+    cpputils::unique_ptr<FreelookSystem>     _freelook_sys;
+    cpputils::unique_ptr<HintSystem>         _hint_sys;
+    cpputils::unique_ptr<InputSystem>        _input_sys;
+    cpputils::unique_ptr<LevelDirector>      _level_director;
+    cpputils::unique_ptr<ParticleSystem>     _particle_sys;
+    cpputils::unique_ptr<PhysicsSystem>      _physics_sys;
+    cpputils::unique_ptr<PlateSystem>        _plate_sys;
+    cpputils::unique_ptr<ProgramSystem>      _program_sys;
+    cpputils::unique_ptr<ProjectileSystem>   _projectiles_sys;
+    cpputils::unique_ptr<PultSystem>         _pult_sys;
+    cpputils::unique_ptr<WordAiSystem>       _word_ai_sys;
+    cpputils::unique_ptr<WordAnimSystem>     _word_anim_sys;
 
     bool     _editor_hidden  { false };
     uint64_t _editor_gen     { 0 };
     double   _pick_cooldown  { 0.0 };
     double   _shoot_cooldown { 0.0 };
 
-    std::string    _typing_last;
+    std::string        _typing_last;
 
-    CarriedLine    _carried;
-    EditorWall     _editor_wall;
-    FrameInput     _frame_input;
-    GameContext    _ctx;
-    WallConnection _wall_connection;
-    TextFile       _editor_file;
-    CppHighlightSystem _highlight_sys;
+    CarriedLine        _carried;
+    Wall::Editor         _editor_wall;
+    FrameInput         _frame_input;
+    GameContext        _ctx;
+    WallConnection     _wall_connection;
+    Text::View         _editor_file;
 
 
     DynArray<GameObject*>   _dyn_scenery;
@@ -77,7 +74,7 @@ class GameState : public IState
     DynArray<Vec3>          _freelook_return_from;
     DynArray<std::string>   _editor_absorbed;
     DynArray<Projectile>    _projectiles;
-    DynArray<WallLabel>     _wall_labels;
+    DynArray<Wall::Label>     _wall_labels;
     DynArray<WordAnim_Add>  _anims_add;
     DynArray<WordAnim_Drop> _anims_drop;
 
@@ -128,9 +125,9 @@ class GameState : public IState
     void projectile_LandOnWall      (ProjectileResult&);
     void projectile_LandOnWallText  (ProjectileResult&, DynArray<size_t>& wall_text_to_erase);
 
-    void pult_DispatchAction (PultAction act);
+    void pult_DispatchAction(PultAction act);
 
-    void debug_SpawnWords    (size_t n);
+    void debug_SpawnWords   (size_t n);
 
     void handle_Input       (FrameInput&, double dt);
     void update_PlayerCamera(FrameInput& input, double dt);
diff --git a/src/states/istate.hpp b/src/states/istate.hpp
index bf8b062..2e483ce 100644
--- a/src/states/istate.hpp
+++ b/src/states/istate.hpp
@@ -2,9 +2,11 @@
 
 #include <SDL3/SDL.h>
 
+
 class Game;
 class GlRenderer;
 
+
 class IState
 {
 public:
diff --git a/src/states/menu_state.cpp b/src/states/menu_state.cpp
index ed5e474..7e0e3c1 100644
--- a/src/states/menu_state.cpp
+++ b/src/states/menu_state.cpp
@@ -95,9 +95,9 @@ MenuState::build_Items()
         _items.push_back(std::move(mi));
     }
 
-    for (size_t i = 0; i < Level::level_Count(); ++i) {
+    for (size_t i = 0; i < Level::get_Count(); ++i) {
         MenuItem mi;
-        mi.label       = Level::get_Level(i).name;
+        mi.label       = Level::get_Data(i).name;
         mi.kind        = ItemKind::StartLevel;
         mi.level_index = i;
         mi.slot_pos    = slot_PosForColumn(COLUMN_MID_RAD, EYE_Y);
@@ -168,8 +168,8 @@ MenuState::handle_Event(Game& game, const SDL_Event& e)
         case SDLK_DOWN:
             if (is_LevelItem(pick_FromCrosshair())) {
                 const double max_scroll =
-                    static_cast<double>(Level::level_Count() > 0
-                                        ? Level::level_Count() - 1 : 0);
+                    static_cast<double>(Level::get_Count() > 0
+                                        ? Level::get_Count() - 1 : 0);
                 if (_scroll_target < max_scroll) _scroll_target += 1.0;
             }
             break;
@@ -238,8 +238,8 @@ MenuState::pick_FromCrosshair() const
     for (size_t i = 0; i < _items.size(); ++i) {
         if (!_items[i].text3d || !_items[i].text3d->loaded) continue;
 
-        const Vec3 mn = _items[i].text3d->aabb_min();
-        const Vec3 mx = _items[i].text3d->aabb_max();
+        const Vec3 mn = _items[i].text3d->aabb_Min();
+        const Vec3 mx = _items[i].text3d->aabb_Max();
 
         double tmin = 0.0, tmax = 1e9;
         const double ox = _camera->pos.x;
diff --git a/src/states/menu_state.hpp b/src/states/menu_state.hpp
index cf26887..1050634 100644
--- a/src/states/menu_state.hpp
+++ b/src/states/menu_state.hpp
@@ -13,32 +13,32 @@
 
 class MenuState : public IState
 {
-    enum class ItemKind : uint8_t {
+    enum class ItemKind : uint8_t
+    {
         OpenFile,
         StartLevel,
         Quit,
     };
 
-    struct MenuItem {
-        std::string label;
+    struct MenuItem
+    {
         ItemKind    kind;
         size_t      level_index = 0;
         Text3dPtr   text3d;
         Vec3        slot_pos {};
+        std::string label;
     };
 
     cpputils::unique_ptr<World>  _world;
     cpputils::unique_ptr<Camera> _camera;
     cpputils::unique_ptr<Light>  _light;
-
-    Text3dPtr          _title;
-    DynArray<MenuItem> _items;
-    size_t             _selected{0};
-
+    Text3dPtr                    _title;
+    size_t _selected      {0};
     double _scroll_current{0.0};
     double _scroll_target {0.0};
+    double _t             {0.0};
 
-    double _t{0.0};
+    DynArray<MenuItem> _items;
 
     void   build_Items ();
     void   activate    (Game& game);
diff --git a/src/systems/aim.hpp b/src/systems/aim.hpp
index bf54bd1..cbb1641 100644
--- a/src/systems/aim.hpp
+++ b/src/systems/aim.hpp
@@ -7,37 +7,39 @@
 #include "systems/collision.hpp"
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
-#include "utils/math.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
 
 namespace Aim
 {
 
-struct Result {
+
+struct Result
+{
     Text3d* track { nullptr };
 
     Vec3 point {};
     Vec3 local {};
 };
 
+
 inline Result
 crosshair_Target(const Camera& camera,
                  const DynArray<Text3dPtr>&     words,
                  const DynArray<GameObjectPtr>& scenery,
-                 const DynArray<TextWallPtr>&   wall_texts,
+                 const DynArray<Wall::Ptr>&   wall_texts,
                  float world_scale)
 {
     const Vec3   eye = camera.pos;
     const Vec3   dir = camera.fwd;
     const double ws  = static_cast<double>(world_scale);
 
-    // 1. Distance along the ray to the box surface (nearest bounding plane).
     double wall_t = 1e18;
     auto plane = [&](double o, double d) {
         if (SDL_fabs(d) < 1e-9) return;
         const double t = SDL_max((ws - o) / d, (-ws - o) / d);
         if (t > 0.0 && t < wall_t) wall_t = t;
     };
+
     plane(eye.x, dir.x);
     plane(eye.y, dir.y);
     plane(eye.z, dir.z);
@@ -46,9 +48,10 @@ crosshair_Target(const Camera& camera,
     const Vec3 seg { dir.x * wall_t, dir.y * wall_t, dir.z * wall_t };
 
     Result out;
-    out.point   = Vec3{ eye.x + seg.x, eye.y + seg.y, eye.z + seg.z };   // wall point
-    double best_t = 1.0;                                                 // seg-fraction
-    Text3d* win   = nullptr;                                             // winning word, if any
+    out.point = Vec3{ eye.x + seg.x, eye.y + seg.y, eye.z + seg.z };
+
+    double  best_t = 1.0;
+    Text3d* win    = nullptr;
 
     auto test = [&](const Vec3& mn, const Vec3& mx, Text3d* obj) {
         Collision::SweptResult sw = Collision::swept_RayAabb(eye, seg, mn, mx);
@@ -62,11 +65,11 @@ crosshair_Target(const Camera& camera,
     };
 
     for (const Text3dPtr& w : words)
-        if (w) test(w->aabb_min(), w->aabb_max(), w.get());
+        if (w) test(w->aabb_Min(), w->aabb_Max(), w.get());
     for (const GameObjectPtr& s : scenery)
-        if (s) test(s->aabb_min(), s->aabb_max(), nullptr);
-    for (const TextWallPtr& wt : wall_texts)
-        if (wt && wt->text3d) test(wt->text3d->aabb_min(), wt->text3d->aabb_max(), nullptr);
+        if (s) test(s->aabb_Min(), s->aabb_Max(), nullptr);
+    for (const Wall::Ptr& wt : wall_texts)
+        if (wt && wt->text3d) test(wt->text3d->aabb_Min(), wt->text3d->aabb_Max(), nullptr);
 
     if (win) {
         out.track = win;
diff --git a/src/systems/carry_system.cpp b/src/systems/carry_system.cpp
index a564c37..ea84023 100644
--- a/src/systems/carry_system.cpp
+++ b/src/systems/carry_system.cpp
@@ -7,6 +7,7 @@ CarriedLine::empty() const
     return size == 0;
 }
 
+
 void
 CarriedLine::push(Text3dPtr w)
 {
@@ -24,6 +25,7 @@ CarriedLine::push(Text3dPtr w)
     size++;
 }
 
+
 Text3dPtr
 CarriedLine::pop_back()
 {
@@ -54,6 +56,7 @@ CarriedLine::pop_back()
     return word;
 }
 
+
 Text3dPtr
 CarriedLine::pop_front()
 {
@@ -74,6 +77,7 @@ CarriedLine::pop_front()
     return word;
 }
 
+
 DynArray<CarriedWordNode*>
 CarriedLine::nodes() const
 {
@@ -103,6 +107,7 @@ CarriedLine::clear()
     size = 0;
 }
 
+
 void
 CarriedLine::compact()
 {
diff --git a/src/systems/carry_system.hpp b/src/systems/carry_system.hpp
index 7e81a21..06e53eb 100644
--- a/src/systems/carry_system.hpp
+++ b/src/systems/carry_system.hpp
@@ -1,19 +1,21 @@
 #pragma once
-#include <memory>
 
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
 
 
 
-struct CarriedWordNode {
+struct CarriedWordNode
+{
     Text3dPtr word;
     CarriedWordNode* prev{nullptr};
     cpputils::unique_ptr<CarriedWordNode> next;
     CarriedWordNode(Text3dPtr w) : word(std::move(w)) {}
 };
 
-struct CarriedLine {
+
+struct CarriedLine
+{
     cpputils::unique_ptr<CarriedWordNode> first;
     CarriedWordNode* last{nullptr};
     size_t size{0};
diff --git a/src/systems/celebration_system.cpp b/src/systems/celebration_system.cpp
index 50295b9..2538ae9 100644
--- a/src/systems/celebration_system.cpp
+++ b/src/systems/celebration_system.cpp
@@ -92,14 +92,14 @@ CelebrationSystem::finish(ParticleSystem& particle_sys)
 
 
 bool
-CelebrationSystem::active() const
+CelebrationSystem::is_Active() const
 {
     return _active;
 }
 
 
 double
-CelebrationSystem::progress() const
+CelebrationSystem::get_Progress() const
 {
     return (_duration > 0.0) ? (_t / _duration) : 1.0;
 }
diff --git a/src/systems/celebration_system.hpp b/src/systems/celebration_system.hpp
index dca732a..9a24e9a 100644
--- a/src/systems/celebration_system.hpp
+++ b/src/systems/celebration_system.hpp
@@ -2,13 +2,14 @@
 
 #include "utils/globals.hpp"
 
-struct Light;
-struct Camera;
-class  ParticleSystem;
 class  GlRenderer;
+class  ParticleSystem;
+struct Camera;
+struct Light;
 
 
-class CelebrationSystem {
+class CelebrationSystem
+{
     bool      _active     = false;
     double    _t          = 0,
               _duration   = 3.5,
@@ -18,7 +19,8 @@ public:
     void   start   (const Camera& cam, double& glyph_yaw);
     void   tick    (double dt, ParticleSystem& particle_sys);
     void   finish  (ParticleSystem& particle_sys);
-    bool   active  () const;
-    double progress() const;
     void   draw    (GlRenderer&, const Camera&, const Light&) const;
+
+    bool   is_Active   () const;
+    double get_Progress() const;
 };
diff --git a/src/systems/collision.cpp b/src/systems/collision.cpp
index d2b554a..1aa158b 100644
--- a/src/systems/collision.cpp
+++ b/src/systems/collision.cpp
@@ -1,9 +1,8 @@
-#include "systems/collision.hpp"
-
 #include <SDL3/SDL.h>
 #include <algorithm>
 
 #include "entities/game_object.hpp"
+#include "systems/collision.hpp"
 
 
 namespace Collision
@@ -14,12 +13,12 @@ static constexpr double FRICTION_IMPULSE_CUTOFF = 2.0;
 bool
 aabb_Overlap(const GameObject& a, const GameObject& b)
 {
-    return a.aabb_min().x <= b.aabb_max().x &&
-           a.aabb_max().x >= b.aabb_min().x &&
-           a.aabb_min().y <= b.aabb_max().y &&
-           a.aabb_max().y >= b.aabb_min().y &&
-           a.aabb_min().z <= b.aabb_max().z &&
-           a.aabb_max().z >= b.aabb_min().z;
+    return a.aabb_Min().x <= b.aabb_Max().x &&
+           a.aabb_Max().x >= b.aabb_Min().x &&
+           a.aabb_Min().y <= b.aabb_Max().y &&
+           a.aabb_Max().y >= b.aabb_Min().y &&
+           a.aabb_Min().z <= b.aabb_Max().z &&
+           a.aabb_Max().z >= b.aabb_Min().z;
 }
 
 
@@ -28,12 +27,12 @@ aabb_Manifold(const GameObject& a, const GameObject& b)
 {
     Manifold m;
 
-    double ox = std::min(a.aabb_max().x, b.aabb_max().x) -
-                std::max(a.aabb_min().x, b.aabb_min().x);
-    double oy = std::min(a.aabb_max().y, b.aabb_max().y) -
-                std::max(a.aabb_min().y, b.aabb_min().y);
-    double oz = std::min(a.aabb_max().z, b.aabb_max().z) -
-                std::max(a.aabb_min().z, b.aabb_min().z);
+    double ox = SDL_min(a.aabb_Max().x, b.aabb_Max().x) -
+                SDL_max(a.aabb_Min().x, b.aabb_Min().x);
+    double oy = SDL_min(a.aabb_Max().y, b.aabb_Max().y) -
+                SDL_max(a.aabb_Min().y, b.aabb_Min().y);
+    double oz = SDL_min(a.aabb_Max().z, b.aabb_Max().z) -
+                SDL_max(a.aabb_Min().z, b.aabb_Min().z);
 
     if (ox <= 0.0 || oy <= 0.0 || oz <= 0.0)
         return m;
@@ -85,7 +84,7 @@ resolve_Objects(GameObject& a, GameObject& b)
 
     if (rel_vel >= 0.0) return;  // already separating
 
-    double e          = std::min(a.body.restitution, b.body.restitution);
+    double e          = SDL_min(a.body.restitution, b.body.restitution);
     double inv_mass_a = a_static ? 0.0 : 1.0 / a.body.mass;
     double inv_mass_b = b_static ? 0.0 : 1.0 / b.body.mass;
     double j          = -(1.0 + e) * rel_vel / (inv_mass_a + inv_mass_b);
diff --git a/src/systems/collision.hpp b/src/systems/collision.hpp
index ae8e8a0..1bb04d6 100644
--- a/src/systems/collision.hpp
+++ b/src/systems/collision.hpp
@@ -1,26 +1,28 @@
 #pragma once
 
-#include "utils/math.hpp"
+#include "utils/globals.hpp"
 
 class GameObject;
 
 namespace Collision
 {
-    struct Manifold {
+    struct Manifold
+    {
         bool   hit     = false;
         double overlap {};
         Vec3   normal  {};
     };
 
-    struct SweptResult {
+    struct SweptResult
+    {
         bool   hit    = false;
-        double t      = 0.0;     // entry time clamped to [0, 1]
-        Vec3   normal {};        // outward-facing normal of the entry face
+        double t      = 0.0;
+        Vec3   normal {};
     };
 
+    void        resolve_Objects(GameObject& a, GameObject& b);
     bool        aabb_Overlap (const GameObject& a, const GameObject& b);
     Manifold    aabb_Manifold(const GameObject& a, const GameObject& b);
-    void        resolve_Objects(GameObject& a, GameObject& b);
     Vec3        reflect      (const Vec3& vel, const Vec3& normal, double restitution);
     SweptResult swept_RayAabb(const Vec3& origin, const Vec3& dir,
                               const Vec3& box_min, const Vec3& box_max);
diff --git a/src/systems/compiler_system.cpp b/src/systems/compiler_system.cpp
index 554008c..35d5602 100644
--- a/src/systems/compiler_system.cpp
+++ b/src/systems/compiler_system.cpp
@@ -3,7 +3,7 @@
 
 #include "systems/compiler_system.hpp"
 #include "text_3d/text_3d.hpp"
-#include "utils/ascii.hpp"
+#include "utils/text.hpp"
 
 
 CompilerSystem::~CompilerSystem()
@@ -13,7 +13,7 @@ CompilerSystem::~CompilerSystem()
 
 
 void
-CompilerSystem::compile(TextWallList& texts, const std::string& src)
+CompilerSystem::compile(Wall::PtrList& texts, const std::string& src)
 {
     // One compile at a time. Reap a finished worker; ignore re-triggers while
     // one is still running.
@@ -25,8 +25,8 @@ CompilerSystem::compile(TextWallList& texts, const std::string& src)
     // Clear previous output from the compiler wall (main thread — GL-owned).
     texts.erase(
         std::remove_if(texts.begin(), texts.end(),
-            [](const TextWallPtr& wt) {
-                return wt->wall_position == Wall::position_of(Wall::Role::Compiler);
+            [](const Wall::Ptr& wt) {
+                return wt->wall_position == Wall::position_Of(Wall::Role::Compiler);
             }),
         texts.end());
     _count = 0;
@@ -86,7 +86,7 @@ CompilerSystem::run_Compile(CompilerSystem* self, std::string src)
 
 
 void
-CompilerSystem::update(TextWallList& texts)
+CompilerSystem::update(Wall::PtrList& texts)
 {
     // Drain whatever the worker produced and render it (main thread, GL-safe).
     DynArray<std::string> lines;
@@ -102,13 +102,13 @@ CompilerSystem::update(TextWallList& texts)
 
 
 void
-CompilerSystem::push_Line(TextWallList& texts, const std::string& line)
+CompilerSystem::push_Line(Wall::PtrList& texts, const std::string& line)
 {
     if (line == "OK") last_compile_ok = true;
 
-    std::string clean = ascii_Sanitize(line);
+    std::string clean = Text::ascii_Sanitize(line);
 
-    for (TextWallPtr& wt : texts)
+    for (Wall::Ptr& wt : texts)
         if (wt->role == Wall::Role::Compiler)
             wt->text3d->pos.y += static_cast<double>(line_height);
 
@@ -120,7 +120,7 @@ CompilerSystem::push_Line(TextWallList& texts, const std::string& line)
     Text3dPtr t = make_Text3d(clean, Text3d::depth_compiler, 0.003f, pos, ConfigColor::white);
     t->yaw = tf.yaw;
 
-    texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+    texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
         tf.wall_position, Wall::Role::Compiler, std::move(t) }));
     _count++;
 }
diff --git a/src/systems/compiler_system.hpp b/src/systems/compiler_system.hpp
index af125c6..e835fd0 100644
--- a/src/systems/compiler_system.hpp
+++ b/src/systems/compiler_system.hpp
@@ -1,24 +1,25 @@
 #pragma once
-#include <string>
+
+#include <atomic>
 #include <cstdio>
-#include <thread>
 #include <mutex>
-#include <atomic>
+#include <string>
+#include <thread>
 
 #include "entities/world.hpp"
 #include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+
 
 struct CompilerSystem
 {
 private:
-    int                   _count {0};
+    int                   _count  {0};
     std::atomic<bool>     _running{false};
     std::mutex            _mtx;
     std::thread           _worker;
     DynArray<std::string> _pending;
 
-    void        push_Line  (TextWallList&, const std::string& line);
+    void        push_Line  (Wall::PtrList&, const std::string& line);
     static void run_Compile(CompilerSystem* self, std::string src);
 public:
     static inline float line_height = 0.4f;
@@ -26,8 +27,10 @@ public:
 
     bool last_compile_ok{false};
 
-    ~CompilerSystem();
-    void update    (TextWallList&);
-    void compile   (TextWallList&, const std::string& src);
+    void update    (Wall::PtrList&);
+    void compile   (Wall::PtrList&, const std::string& src);
+
     bool is_Running() const { return _running.load(); }
+
+    ~CompilerSystem();
 };
diff --git a/src/systems/cpp_highlight_system.hpp b/src/systems/cpp_highlight_system.hpp
index baf3268..f7a8f89 100644
--- a/src/systems/cpp_highlight_system.hpp
+++ b/src/systems/cpp_highlight_system.hpp
@@ -8,36 +8,37 @@
 #include "cpp_token/cpp_highlight.hpp"
 #include "utils/globals.hpp"
 
-class CppHighlightSystem {
+
+class CppHighlightSystem
+{
 public:
     ~CppHighlightSystem() { if (_worker.joinable()) _worker.join(); }
 
-    // Request a lex of `source` tagged with `gen`. No-op if source unchanged
-    // since last request. Single-flight: coalesces while a lex is in flight.
     void request(const std::string& source, uint64_t gen)
     {
-        if (source == _last_requested) return;     // content unchanged → skip
+        // TODO: dont send a request twice?!
+        if (source == _last_requested) return;
         _last_requested = source;
 
-        if (_running.load()) { _redo = true; return; }   // coalesce
+        if (_running.load()) { _redo = true; return; }
         spawn(source, gen);
     }
 
-    // Drain finished results. Returns true + fills out if a lex completed this
-    // call; caller checks gen against current content before applying.
     bool poll(DynArray<HiSpan>& out, uint64_t& out_gen)
     {
         if (!_done.load()) return false;
+
         {
             std::lock_guard<std::mutex> lk(_mtx);
             out     = _pending;
             out_gen = _result_gen;
         }
+
         _done.store(false);
         if (_worker.joinable()) _worker.join();
         _running.store(false);
 
-        if (_redo) {                       // content changed mid-lex → relex
+        if (_redo) {
             _redo = false;
             spawn(_last_requested, _last_gen_pending);
         }
@@ -45,6 +46,16 @@ public:
     }
 
 private:
+    bool              _redo    { false };
+    std::atomic<bool> _running { false };
+    std::atomic<bool> _done    { false };
+    uint64_t          _result_gen { 0 };
+    uint64_t          _last_gen_pending { 0 };
+    std::thread       _worker;
+    std::mutex        _mtx;
+    std::string       _last_requested;
+    DynArray<HiSpan>  _pending;
+
     void spawn(const std::string& source, uint64_t gen)
     {
         if (_worker.joinable()) _worker.join();
@@ -62,13 +73,4 @@ private:
         });
     }
 
-    std::thread       _worker;
-    std::mutex        _mtx;
-    std::atomic<bool> _running { false };
-    std::atomic<bool> _done    { false };
-    DynArray<HiSpan>  _pending;
-    uint64_t          _result_gen { 0 };
-    uint64_t          _last_gen_pending { 0 };
-    std::string       _last_requested;
-    bool              _redo { false };
 };
diff --git a/src/systems/dyn_loader_system.cpp b/src/systems/dyn_loader_system.cpp
index 307175a..8109e3a 100644
--- a/src/systems/dyn_loader_system.cpp
+++ b/src/systems/dyn_loader_system.cpp
@@ -7,7 +7,7 @@
 #include "entities/world.hpp"
 #include "systems/dyn_loader_system.hpp"
 #include "text_3d/text_3d.hpp"
-#include "utils/ascii.hpp"
+#include "utils/text.hpp"
 
 
 // Where game_mod_abi.h is installed at runtime, and the build scratch dir.
@@ -64,15 +64,15 @@ DynLoaderSystem::wrap_Source(const std::string& user_body)
 
 
 void
-DynLoaderSystem::build(TextWallList& texts, const std::string& user_src, bool full_source)
+DynLoaderSystem::build(Wall::PtrList& texts, const std::string& user_src, bool full_source)
 {
     last_build_ok = false;
 
     // Clear previous output from the Compiler wall.
     texts.erase(
         std::remove_if(texts.begin(), texts.end(),
-            [](const TextWallPtr& wt) {
-                return wt->wall_position == Wall::position_of(Wall::Role::Compiler);
+            [](const Wall::Ptr& wt) {
+                return wt->wall_position == Wall::position_Of(Wall::Role::Compiler);
             }),
         texts.end());
     _count = 0;
@@ -110,7 +110,7 @@ DynLoaderSystem::build(TextWallList& texts, const std::string& user_src, bool fu
 
 
 void
-DynLoaderSystem::update(TextWallList& texts)
+DynLoaderSystem::update(Wall::PtrList& texts)
 {
     if (!_pipe) return;
 
@@ -142,10 +142,10 @@ DynLoaderSystem::update(TextWallList& texts)
 
 
 void
-DynLoaderSystem::push_Line(TextWallList& texts, const std::string& line)
+DynLoaderSystem::push_Line(Wall::PtrList& texts, const std::string& line)
 {
     // Shift existing compiler lines up, drop the new one at the bottom.
-    for (TextWallPtr& wt : texts)
+    for (Wall::Ptr& wt : texts)
         if (wt->role == Wall::Role::Compiler)
             wt->text3d->pos.y += static_cast<double>(line_height);
 
@@ -153,12 +153,12 @@ DynLoaderSystem::push_Line(TextWallList& texts, const std::string& line)
     Vec3 pos = tf.position;
     pos.y = start_y;
 
-    std::string clean = ascii_Sanitize(line);
+    std::string clean = Text::ascii_Sanitize(line);
     Text3dPtr t = make_Text3d(clean, Text3d::depth_compiler, 0.003f,
                               pos, ConfigColor::compiler);
     t->yaw = tf.yaw;
 
-    texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+    texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
         tf.wall_position,
         Wall::Role::Compiler,
         std::move(t)
diff --git a/src/systems/dyn_loader_system.hpp b/src/systems/dyn_loader_system.hpp
index 66ab185..183e4fa 100644
--- a/src/systems/dyn_loader_system.hpp
+++ b/src/systems/dyn_loader_system.hpp
@@ -1,11 +1,11 @@
 #pragma once
 
-#include <cstdio>
 #include <string>
 
 #include "systems/game_mod_abi.h"
 #include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
+
 
 class DynLoaderSystem
 {
@@ -15,28 +15,29 @@ class DynLoaderSystem
     FILE* _pipe   { nullptr };
     void* _handle { nullptr };
 
-    int _count { 0 };
+    int _count        { 0 };
     int _build_serial { 0 };
 
     std::string _pending_so;
     std::string _last_so_path;
 
 
+    void push_Line  (Wall::PtrList& texts, const std::string& line);
     static std::string
          wrap_Source(const std::string& user_body);
-    void push_Line  (TextWallList& texts, const std::string& line);
 
 public:
     bool last_build_ok { false };
 
-    void build       (TextWallList& texts, const std::string& user_src, bool full_source);
-    void update      (TextWallList& texts);
-    bool is_Running  () const { return _pipe != nullptr; }
-    const std::string&
-         last_so_path() const { return _last_so_path; }
+    void build       (Wall::PtrList& texts, const std::string& user_src, bool full_source);
+    void update      (Wall::PtrList& texts);
 
     DynArray<DynObject>
          load_Objects();
 
+    bool is_Running    () const { return _pipe != nullptr; }
+    const std::string&
+         get_LastSoPath() const { return _last_so_path; }
+
     ~DynLoaderSystem();
 };
diff --git a/src/systems/freelook_system.cpp b/src/systems/freelook_system.cpp
index 42e0de5..f505d10 100644
--- a/src/systems/freelook_system.cpp
+++ b/src/systems/freelook_system.cpp
@@ -1,7 +1,9 @@
-#include "freelook_system.hpp"
 #include <SDL3/SDL.h>
 #include <algorithm>
 
+#include "freelook_system.hpp"
+
+
 static constexpr double
 FREELOOK_LERP_DUR = 0.20;
 
diff --git a/src/systems/freelook_system.hpp b/src/systems/freelook_system.hpp
index facedb5..de6a668 100644
--- a/src/systems/freelook_system.hpp
+++ b/src/systems/freelook_system.hpp
@@ -1,16 +1,18 @@
 #pragma once
-#include <cstdint>
-#include "utils/math.hpp"
+
+#include "utils/globals.hpp"
 #include "systems/carry_system.hpp"
 
-struct FreelookState {
-    bool   active{};
+struct FreelookState
+{
+    bool   active {};
     bool   lerping{};
-    double lerp_t{};
+    double lerp_t {};
 };
 
 
-class FreelookSystem {
+class FreelookSystem
+{
 public:
     FreelookState state;
 
diff --git a/src/systems/hint_system.hpp b/src/systems/hint_system.hpp
index 142345a..8876730 100644
--- a/src/systems/hint_system.hpp
+++ b/src/systems/hint_system.hpp
@@ -5,19 +5,24 @@
 #include "entities/camera.hpp"
 #include "utils/light.hpp"
 
+
 class GlRenderer;
 
-class HintSystem {
+
+class HintSystem
+{
     std::string _current_hint;
     TextLabel   _label;
 
 public:
     HintSystem   ();
 
-    void set_Hint(const std::string& hint_text);
     void clear   ();
     void update  (double dt, const Camera& camera);
     void draw    (GlRenderer& gl, const Camera& camera, const Light& light) const;
+
+    void set_Hint(const std::string& hint_text);
+
     TextLabel&
          get_Label()       { return _label; }
     const TextLabel&
diff --git a/src/systems/input_system.hpp b/src/systems/input_system.hpp
index 150e561..11fcea2 100644
--- a/src/systems/input_system.hpp
+++ b/src/systems/input_system.hpp
@@ -5,9 +5,12 @@
 
 #include "utils/globals.hpp"
 
+
 class Game;
 
-enum class InputCommand : uint8_t {
+
+enum class InputCommand : uint8_t
+{
     Jump,
     Click,
     Drop,
@@ -24,7 +27,8 @@ enum class InputCommand : uint8_t {
 };
 
 
-struct FrameInput {
+struct FrameInput
+{
     bool forward  = false;
     bool backward = false;
     bool left     = false;
@@ -46,7 +50,8 @@ struct FrameInput {
     DynArray<InputCommand> commands;
 };
 
-class InputSystem {
-public:
+
+struct InputSystem
+{
     void handle_Event(Game& game, const SDL_Event& e, FrameInput& input);
 };
diff --git a/src/systems/level_director.cpp b/src/systems/level_director.cpp
index d2d1766..ef75de5 100644
--- a/src/systems/level_director.cpp
+++ b/src/systems/level_director.cpp
@@ -1,4 +1,3 @@
-#include "systems/level_director.hpp"
 
 #include <algorithm>
 #include <unordered_set>
@@ -7,13 +6,14 @@
 #include "entities/plate.hpp"
 #include "entities/solid_box.hpp"
 #include "entities/world.hpp"
-#include "levels/level_check.hpp"
+#include "levels/level.hpp"
 #include "states/game_context.hpp"
 #include "systems/celebration_system.hpp"
+#include "systems/level_director.hpp"
 #include "systems/particle_system.hpp"
 #include "utils/config.hpp"
-#include "utils/text_wrap.hpp"
-#include "wall/text_wall.hpp"
+#include "utils/text.hpp"
+#include "wall/wall.hpp"
 
 
 LevelDirector::LevelDirector(const Level::Data& level)
@@ -24,8 +24,8 @@ LevelDirector::LevelDirector(const Level::Data& level)
 int
 LevelDirector::get_MaxAiForStep() const
 {
-    if (_runner->complete()) return 0;
-    return _runner->current().max_ai_words;
+    if (_runner->is_Complete()) return 0;
+    return _runner->get_Current().max_ai_words;
 }
 
 
@@ -33,7 +33,7 @@ void
 LevelDirector::enter_Step(GameContext& ctx)
 {
     spawn_Grants(ctx);
-    setup_Scene(ctx, _runner->current().scene);
+    setup_Scene(ctx, _runner->get_Current().scene);
     show_Details(ctx);
     _step_age = 0.0;
 }
@@ -42,7 +42,7 @@ LevelDirector::enter_Step(GameContext& ctx)
 void
 LevelDirector::spawn_Grants(GameContext& ctx)
 {
-    DynArray<std::string> tokens = _runner->garants_ForStep();
+    DynArray<std::string> tokens = _runner->get_GarantsForStep();
 
     static constexpr float spacing = 3.0f;
     static constexpr int   per_row = 8;
@@ -69,15 +69,15 @@ LevelDirector::spawn_Grants(GameContext& ctx)
 
 
 void
-LevelDirector::setup_Scene(GameContext& ctx, const Scene& scene)
+LevelDirector::setup_Scene(GameContext& ctx, const Scene::Data& scene)
 {
-    for (const PlacedWord& pw : scene.words) {
+    for (const Scene::Placed::Word& pw : scene.words) {
         Text3dPtr t = make_Text3d(pw.text, Text3d::depth_floor, 0.003f, pw.pos, pw.color);
         t->body.hover_height = pw.pos.y;
         ctx.words.push_back(std::move(t));
     }
 
-    for (const PlacedPlate& pp : scene.plates) {
+    for (const Scene::Placed::Plate& pp : scene.plates) {
         auto plate = cpputils::make_unique<Plate>(pp.pos);
         Plate* raw = plate.get();
         _step_plates .push_back({ raw, pp.tag });
@@ -85,7 +85,7 @@ LevelDirector::setup_Scene(GameContext& ctx, const Scene& scene)
         ctx.scenery  .push_back(std::move(plate));
     }
 
-    for (const PlacedPlatform& pl : scene.platforms) {
+    for (const Scene::Placed::Platform& pl : scene.platforms) {
         auto box = cpputils::make_unique<SolidBox>(pl.pos, pl.half_extents,
                                                    pl.fill_color, pl.wire_color);
         GameObject* raw = box.get();
@@ -93,7 +93,7 @@ LevelDirector::setup_Scene(GameContext& ctx, const Scene& scene)
         ctx.scenery  .push_back(std::move(box));
     }
 
-    for (const PlacedAi& a : scene.ai_seeds) {
+    for (const Scene::Placed::Ai& a : scene.ai_seeds) {
         Text3dPtr t = make_Text3d(a.text, Text3d::depth_floor, 0.003f, a.pos, ConfigColor::floor);
         t->body.hover_height = a.pos.y;
         t->ai.aggressiveness = a.aggressiveness;
@@ -143,15 +143,15 @@ LevelDirector::show_Details(GameContext& ctx) const
 {
     ctx.clear_WallRole(Wall::Role::Info);
 
-    if (_runner->complete()) return;
+    if (_runner->is_Complete()) return;
 
-    const std::string& details = _runner->current().details;
+    const std::string& details = _runner->get_Current().details;
     if (details.empty()) return;
 
     Wall::Transform wt = Wall::get_Transform(Wall::Role::Info, World::get_BoxScale());
 
     constexpr size_t MAX_INFO_LINE_CHARS = 92;
-    DynArray<std::string> lines = wrap_Text(details, MAX_INFO_LINE_CHARS);
+    DynArray<std::string> lines = Text::wrap_String(details, MAX_INFO_LINE_CHARS);
 
     const float bottom_y = World::get_FloorY() + 1.0f;
     float y = bottom_y + static_cast<float>(lines.size() - 1) * ConfigWall::text_line_spacing;
@@ -169,10 +169,10 @@ LevelDirector::show_Details(GameContext& ctx) const
 }
 
 
-GoalContext
+Goal::Context
 LevelDirector::build_GoalCtx(const GameContext& ctx) const
 {
-    GoalContext gctx;
+    Goal::Context gctx;
 
     for (const StepPlate& sp : _step_plates)
         if (sp.plate && sp.plate->active)
@@ -186,8 +186,8 @@ LevelDirector::build_GoalCtx(const GameContext& ctx) const
     gctx.picked_up_this_step         = _ledger.picked_up;
 
     if (gctx.compile_ok_this_step) {
-        std::string src = TextWall::extract_Text(ctx.wall_texts, Wall::Role::Editor);
-        gctx.editor_normalized = LevelCheck::normalize(src);
+        std::string src = Wall::Text::extract_Text(ctx.wall_texts, Wall::Role::Editor);
+        gctx.editor_normalized = Level::Check::normalize(src);
     }
     return gctx;
 }
@@ -200,8 +200,8 @@ LevelDirector::try_Advance(GameContext& ctx, double dt,
     _step_age += dt;
     AdvanceResult res;
 
-    if (celebration.active()) {
-        if (celebration.progress() >= 1.0) {
+    if (celebration.is_Active()) {
+        if (celebration.get_Progress() >= 1.0) {
             celebration.finish(particles);
 
             teardown_Scene(ctx);
@@ -209,16 +209,16 @@ LevelDirector::try_Advance(GameContext& ctx, double dt,
 
             res.stepped     = true;
             res.advanced    = _runner->advance();
-            res.reset_carry = res.advanced && _runner->current().reset_carry;
+            res.reset_carry = res.advanced && _runner->get_Current().reset_carry;
             _step_age       = 0.0;
         }
         return res;
     }
 
-    if (_runner->complete()) return res;
+    if (_runner->is_Complete()) return res;
 
-    GoalContext gctx = build_GoalCtx(ctx);
-    if (!goal_Satisfied(_runner->current().goal, gctx)) return res;
+    Goal::Context gctx = build_GoalCtx(ctx);
+    if (!Goal::is_Satisfied(_runner->get_Current().goal, gctx)) return res;
     if (_step_age < ConfigLevel::settle_time_for_step)  return res;
 
     double glyph_yaw = SDL_atan2(-ctx.camera->fwd.x, -ctx.camera->fwd.z);
diff --git a/src/systems/level_director.hpp b/src/systems/level_director.hpp
index 76f6ecd..543ce34 100644
--- a/src/systems/level_director.hpp
+++ b/src/systems/level_director.hpp
@@ -10,16 +10,17 @@
 #include "systems/level_runner_system.hpp"
 #include "utils/globals.hpp"
 
-struct GameContext;
-class  Plate;
-class  WordAiSystem;
-class  HintSystem;
+
 class  CelebrationSystem;
+class  HintSystem;
 class  ParticleSystem;
+class  Plate;
+class  WordAiSystem;
+struct GameContext;
 
 
-
-struct StepLedger {
+struct StepLedger
+{
     DynArray<PultAction>  buttons_pressed;
     DynArray<std::string> ai_defeated;
     DynArray<std::string> picked_up;
@@ -29,8 +30,8 @@ struct StepLedger {
 
     void clear() {
         buttons_pressed.clear();
-        ai_defeated.clear();
-        picked_up.clear();
+        ai_defeated    .clear();
+        picked_up      .clear();
         compile_ok = false;
         dropped    = false;
         shot       = false;
@@ -38,7 +39,8 @@ struct StepLedger {
 };
 
 
-struct StepPlate {
+struct StepPlate
+{
     Plate*      plate;
     std::string tag;
 };
@@ -55,10 +57,10 @@ class LevelDirector
     DynArray<GameObject*>  _step_scenery;
 
     void spawn_Grants  (GameContext& ctx);
-    void setup_Scene   (GameContext& ctx, const Scene& scene);
+    void setup_Scene   (GameContext& ctx, const Scene::Data& scene);
     void teardown_Scene(GameContext& ctx);
 
-    GoalContext build_GoalCtx (const GameContext& ctx) const;
+    Goal::Context build_GoalCtx (const GameContext& ctx) const;
 
 public:
     struct AdvanceResult {
@@ -84,10 +86,11 @@ public:
     void record_AiDefeated(const std::string& t) { _ledger.ai_defeated.push_back(t); }
     void record_CompileOk ()                     { _ledger.compile_ok = true; }
 
-    LevelRunner&         runner()             { return *_runner; }
-    const LevelRunner&   runner()       const { return *_runner; }
-    bool                 complete()     const { return _runner->complete(); }
+    bool                 is_LevelComplete() const { return _runner->is_Complete(); }
+
+    LevelRunner&         get_Runner()             { return *_runner; }
+    const LevelRunner&   get_Runner()       const { return *_runner; }
+    const std::string&   get_CurrentHint()  const { return _runner->get_Current().hint; }
     int                  get_MaxAiForStep() const;
-    const std::string&   current_hint() const { return _runner->current().hint; }
-    DynArray<StepPlate>& step_Plates()        { return _step_plates; }
+    DynArray<StepPlate>& get_StepPlates()         { return _step_plates; }
 };
diff --git a/src/systems/level_runner_system.cpp b/src/systems/level_runner_system.cpp
index f66dffe..388d186 100644
--- a/src/systems/level_runner_system.cpp
+++ b/src/systems/level_runner_system.cpp
@@ -2,16 +2,19 @@
 
 LevelRunner::LevelRunner(const Level::Data& l) : _level(&l) {}
 
+
 bool LevelRunner::advance()
 {
     _current_step++;
-    return !complete();
+    return !is_Complete();
 }
 
-DynArray<std::string> LevelRunner::garants_ForStep() const
+
+DynArray<std::string>
+LevelRunner::get_GarantsForStep() const
 {
     DynArray<std::string> result;
-    for (const Level::TokenGrant& grant : current().grants)
+    for (const Level::TokenGrant& grant : get_Current().grants)
         for (const std::string& c : grant.choices)
             result.push_back(c);
     return result;
diff --git a/src/systems/level_runner_system.hpp b/src/systems/level_runner_system.hpp
index c1d6131..5f249a5 100644
--- a/src/systems/level_runner_system.hpp
+++ b/src/systems/level_runner_system.hpp
@@ -1,7 +1,10 @@
 #pragma once
+
 #include "levels/level.hpp"
 
-class LevelRunner {
+
+class LevelRunner
+{
     const Level::Data*
            _level;
 
@@ -9,17 +12,16 @@ class LevelRunner {
 public:
     explicit LevelRunner(const Level::Data& _level);
 
-    bool   advance();
-    bool   complete()    const { return _current_step >= _level->steps.size(); }
+    bool   advance ();
 
-    size_t step()        const { return _current_step; }
-    const Level::Step&
-           current()     const { return _level->steps[_current_step]; }
+    bool   is_Complete   ()  const { return _current_step >= _level->steps.size(); }
+    bool   is_DynamicLib ()  const { return _level->dynamic_lib; }
 
-    bool   dynamic_lib() const { return _level->dynamic_lib; }
+    size_t get_Step      ()   const { return _current_step; }
+    const Level::Step&   
+           get_Current   ()   const { return _level->steps[_current_step]; }
     const std::string&
-           source_file() const { return _level->source_file; }
-
+           get_SourceFile() const { return _level->source_file; }
     DynArray<std::string>
-           garants_ForStep() const;
+           get_GarantsForStep() const;
 };
diff --git a/src/systems/particle_system.cpp b/src/systems/particle_system.cpp
index 4c25ed4..dd96552 100644
--- a/src/systems/particle_system.cpp
+++ b/src/systems/particle_system.cpp
@@ -2,7 +2,6 @@
 
 #include <SDL3/SDL.h>
 #include <algorithm>
-#include <cstdlib>
 
 #include "entities/camera.hpp"
 #include "entities/game_object.hpp"
@@ -90,8 +89,8 @@ ParticleSystem::update(double dt,
         // Cheap point-in-AABB check; particles are tiny so this is fine.
         for (const GameObject* obj : solid_colliders) {
             if (!obj || !obj->solid) continue;
-            const Vec3 mn = obj->aabb_min();
-            const Vec3 mx = obj->aabb_max();
+            const Vec3 mn = obj->aabb_Min();
+            const Vec3 mx = obj->aabb_Max();
             if (p.pos.x >= mn.x && p.pos.x <= mx.x &&
                 p.pos.y >= mn.y && p.pos.y <= mx.y &&
                 p.pos.z >= mn.z && p.pos.z <= mx.z)
@@ -122,7 +121,7 @@ ParticleSystem::draw(GlRenderer& gl, const Camera& cam, const Light& light) cons
     glow.flashlight_intensity = 0.0f;
 
     Mat4 view = buildViewMat4(cam);
-    Mat4 proj = gl.projection();
+    Mat4 proj = gl.get_Projection();
 
     gl.set_Wireframe(false);
     gl.set_Light(glow);
diff --git a/src/systems/particle_system.hpp b/src/systems/particle_system.hpp
index a7b479f..066e125 100644
--- a/src/systems/particle_system.hpp
+++ b/src/systems/particle_system.hpp
@@ -5,38 +5,27 @@
 #include "rendering/gl_renderer.hpp"
 #include "utils/globals.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
+
 
 class Camera;
 class GameObject;
 
 
-// One particle. Lives ~1-2 seconds, falls under gravity, vanishes on
-// collision or when its lifetime expires.
-struct Particle {
+struct Particle
+{
     bool   alive    { true };
     float  yaw      { 0.0f };
-    float  spin     { 0.0f };   // radians/sec
+    float  spin     { 0.0f };
     double age      { 0.0 };
     double lifetime { 1.5 };
 
     Vec3 pos{};
     Vec3 vel{};
+
     SDL_FColor color { 1.0f, 1.0f, 1.0f, 1.0f };
 };
 
 
-// ParticleSystem owns a flat vector of particles.
-// Designed for the success celebration but generic — anyone can emit_Burst.
-//
-// Lifecycle:
-//   update(dt, colliders, world_scale)   — tick physics, kill on hit / lifetime
-//   draw  (gl, cam, light)               — render every alive particle
-//   emit_FireworkBurst(center, color)    — spawn ~80 particles in a sphere
-//
-// Particles ignore everything except: the world bounds (floor/walls/ceiling)
-// and a caller-supplied list of solid GameObjects (so they pop on pults).
-// They do NOT collide with words, AI, or each other — by design.
 class ParticleSystem
 {
     DynArray<Particle> _particles;
@@ -47,7 +36,6 @@ public:
     void clear ();
     bool empty () const { return _particles.empty(); }
     void draw  (GlRenderer& gl, const Camera& cam, const Light& light) const;
-    void emit_FireworkBurst(const Vec3& center,
-                            SDL_FColor color,
-                            int count = 80);
+
+    void emit_FireworkBurst(const Vec3& center, SDL_FColor color, int count = 80);
 };
diff --git a/src/systems/physics_system.cpp b/src/systems/physics_system.cpp
index 394e6e3..5d57e11 100644
--- a/src/systems/physics_system.cpp
+++ b/src/systems/physics_system.cpp
@@ -58,15 +58,15 @@ PhysicsSystem::resolve_PlayerVsObjects(Player& player, CarriedLine& carried,
     for (GameObject* obj : colliders) {
         if (!obj || !obj->solid) continue;
 
-        const Vec3 omin = obj->aabb_min();
-        const Vec3 omax = obj->aabb_max();
+        const Vec3 omin = obj->aabb_Min();
+        const Vec3 omax = obj->aabb_Max();
 
         if (px_max >= omin.x && px_min <= omax.x &&
             py_max >= omin.y && py_min <= omax.y &&
             pz_max >= omin.z && pz_min <= omax.z) {
-            double ox = std::min(px_max, omax.x) - std::max(px_min, omin.x);
-            double oy = std::min(py_max, omax.y) - std::max(py_min, omin.y);
-            double oz = std::min(pz_max, omax.z) - std::max(pz_min, omin.z);
+            double ox = SDL_min(px_max, omax.x) - SDL_max(px_min, omin.x);
+            double oy = SDL_min(py_max, omax.y) - SDL_max(py_min, omin.y);
+            double oz = SDL_min(pz_max, omax.z) - SDL_max(pz_min, omin.z);
 
             Vec3   normal{};
             double overlap{};
@@ -249,17 +249,17 @@ PhysicsSystem::resolve_WorldBounds(GameObject& obj)
     // Floor
     if (obj.pos.y - he.y < -ws) {
         obj.pos.y      = -ws + he.y;
-        obj.body.vel.y = std::abs(obj.body.vel.y) * obj.body.restitution;
+        obj.body.vel.y = SDL_fabs(obj.body.vel.y) * obj.body.restitution;
         obj.body.vel.x *= obj.body.friction;
         obj.body.vel.z *= obj.body.friction;
-        if (std::abs(obj.body.vel.y) < 0.05) obj.body.vel.y = 0.0;
-        if (std::abs(obj.body.vel.x) < 0.01) obj.body.vel.x = 0.0;
-        if (std::abs(obj.body.vel.z) < 0.01) obj.body.vel.z = 0.0;
+        if (SDL_fabs(obj.body.vel.y) < 0.05) obj.body.vel.y = 0.0;
+        if (SDL_fabs(obj.body.vel.x) < 0.01) obj.body.vel.x = 0.0;
+        if (SDL_fabs(obj.body.vel.z) < 0.01) obj.body.vel.z = 0.0;
     }
     // Ceiling
     if (obj.pos.y + he.y > ws) {
         obj.pos.y      =  ws - he.y;
-        obj.body.vel.y = -std::abs(obj.body.vel.y) * obj.body.restitution;
+        obj.body.vel.y = -SDL_fabs(obj.body.vel.y) * obj.body.restitution;
     }
     // Side walls
     if (obj.pos.x + he.x >  ws) { obj.pos.x =  ws - he.x; obj.body.vel.x *= -obj.body.restitution; }
@@ -408,7 +408,7 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
                     constexpr double RESTITUTION_TEXT = 0.55;
                     Vec3 vel_before = proj.vel;
                     Collision::SweptResult sw;
-                    if (resolve_SingleBoxCollision(proj, obj->aabb_min(), obj->aabb_max(),
+                    if (resolve_SingleBoxCollision(proj, obj->aabb_Min(), obj->aabb_Max(),
                                                    word_he, RESTITUTION_TEXT,
                                                    cur, prev, dir, sw)) {
                         proj.collided = true;
@@ -429,7 +429,7 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
                 }
 
                 Collision::SweptResult sw;
-                if (resolve_SingleBoxCollision(proj, obj->aabb_min(), obj->aabb_max(),
+                if (resolve_SingleBoxCollision(proj, obj->aabb_Min(), obj->aabb_Max(),
                                                word_he, RESTITUTION_STATIC,
                                                cur, prev, dir, sw)) {
                     proj.collided = true;
@@ -446,9 +446,9 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
             constexpr double RESTITUTION_LABEL = 0.55;
 
             for (TextLabel* label : *labels) {
-                if (!label || label->empty()) continue;
+                if (!label || label->is_Empty()) continue;
 
-                const auto& lw = label->words();
+                const auto& lw = label->get_Words();
                 for (size_t i = 0; i < lw.size(); ++i) {
                     const Text3dPtr& hw = lw[i];
                     if (!hw || !hw->loaded) continue;
@@ -456,7 +456,7 @@ PhysicsSystem::resolve_Projectiles(DynArray<Projectile>& projectiles,
                     Vec3 vel_before = proj.vel;
                     Collision::SweptResult sw;
 
-                    if (resolve_SingleBoxCollision(proj, hw->aabb_min(), hw->aabb_max(),
+                    if (resolve_SingleBoxCollision(proj, hw->aabb_Min(), hw->aabb_Max(),
                                                    word_he, RESTITUTION_LABEL,
                                                    cur, prev, dir, sw)) {
                         proj.collided = true;
diff --git a/src/systems/physics_system.hpp b/src/systems/physics_system.hpp
index f5fa74b..9c44789 100644
--- a/src/systems/physics_system.hpp
+++ b/src/systems/physics_system.hpp
@@ -6,18 +6,22 @@
 #include "systems/collision.hpp"
 #include "utils/globals.hpp"
 
+
 struct Projectile;
 class  TextLabel;
 
-struct ProjectileContactEvent {
+
+struct ProjectileContactEvent
+{
     Projectile* projectile = nullptr;
     GameObject* other      = nullptr;
     Vec3        point{};
     Vec3        normal{};
 };
 
-class PhysicsSystem {
-    // Uniform spatial grid scratch, reused each frame to avoid reallocation.
+
+class PhysicsSystem
+{
     struct SpatialGrid {
         int    nx    = 0, nz = 0;
         double cell  = 2.0;
@@ -43,12 +47,11 @@ class PhysicsSystem {
     void collide_Grid(const DynArray<GameObject*>& active);
 
 public:
-    void update_Player(Player& player, double acc_x, double acc_z, double dt);
+    void update_Player (Player& player, double acc_x, double acc_z, double dt);
     void update_Objects(const DynArray<GameObject*>& objects,
                         double dt, double gravity);
-
-    void update_Projectiles(DynArray<Projectile>& projectiles, double dt,
-                            const DynArray<Text3dPtr>& words);
+    void update_Projectiles (DynArray<Projectile>& projectiles, double dt,
+                             const DynArray<Text3dPtr>& words);
     void resolve_Projectiles(DynArray<Projectile>& projectiles,
                              const DynArray<GameObject*>* statics,
                              const DynArray<TextLabel*>* labels,
diff --git a/src/systems/pick_system.cpp b/src/systems/pick_system.cpp
index 7267415..8663694 100644
--- a/src/systems/pick_system.cpp
+++ b/src/systems/pick_system.cpp
@@ -60,7 +60,7 @@ PickResult
 pick(const Camera& camera,
      const DynArray<Text3dPtr>&     words,
      const DynArray<GameObjectPtr>& scenery,
-     const DynArray<TextWallPtr>&   wall_texts)
+     const DynArray<Wall::Ptr>&   wall_texts)
 {
     const Vec3& eye = camera.pos;
 
@@ -96,7 +96,7 @@ pick(const Camera& camera,
     }
 
     for (size_t i = 0; i < wall_texts.size(); ++i) {
-        const TextWallPtr& wt = wall_texts[i];
+        const Wall::Ptr& wt = wall_texts[i];
         if (!wt || !wt->text3d)          continue;
         if (wt->text3d->pos.y < floor_y) continue;
         double a = ang_score(*wt->text3d, eye, camera.fwd);
diff --git a/src/systems/pick_system.hpp b/src/systems/pick_system.hpp
index 81a4ed0..fc31e4a 100644
--- a/src/systems/pick_system.hpp
+++ b/src/systems/pick_system.hpp
@@ -1,21 +1,23 @@
 #pragma once
 
-#include <cstddef>
-
 #include "entities/camera.hpp"
 #include "entities/game_object.hpp"
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
+
 
-enum class PickKind : uint8_t {
+enum class PickKind : uint8_t
+{
     None,
     Scenery,
     Wall,
     Word,
 };
 
-struct PickResult {
+
+struct PickResult
+{
     size_t word_index { 0 };
     size_t wall_index { 0 };
 
@@ -25,10 +27,11 @@ struct PickResult {
     bool hit() const { return kind != PickKind::None; }
 };
 
+
 namespace PickSystem
 {
     PickResult pick(const Camera& camera,
                     const DynArray<Text3dPtr>&     words,
                     const DynArray<GameObjectPtr>& scenery,
-                    const DynArray<TextWallPtr>&   wall_texts);
+                    const DynArray<Wall::Ptr>&   wall_texts);
 }
diff --git a/src/systems/plate_system.cpp b/src/systems/plate_system.cpp
index c60f7de..62ee1e1 100644
--- a/src/systems/plate_system.cpp
+++ b/src/systems/plate_system.cpp
@@ -20,8 +20,8 @@ PlateSystem::update(double dt,
 
         plate->tick(dt);
 
-        const Vec3 mn = plate->aabb_min();
-        const Vec3 mx = plate->aabb_max();
+        const Vec3 mn = plate->aabb_Min();
+        const Vec3 mx = plate->aabb_Max();
 
         const bool xz_overlap = px_max >= mn.x && px_min <= mx.x &&
                                  pz_max >= mn.z && pz_min <= mx.z;
diff --git a/src/systems/program_system.cpp b/src/systems/program_system.cpp
index 22095be..09ad3dc 100644
--- a/src/systems/program_system.cpp
+++ b/src/systems/program_system.cpp
@@ -10,7 +10,7 @@
 #include "entities/world.hpp"
 #include "systems/program_system.hpp"
 #include "text_3d/text_3d.hpp"
-#include "utils/ascii.hpp"
+#include "utils/text.hpp"
 #include "utils/config.hpp"
 
 
@@ -38,12 +38,12 @@ ProgramSystem::close_Child()
 
 
 void
-ProgramSystem::run(TextWallList& texts, float world_scale)
+ProgramSystem::run(Wall::PtrList& texts, float world_scale)
 {
     // Clear previous output from the Program wall.
     texts.erase(
         std::remove_if(texts.begin(), texts.end(),
-            [](const TextWallPtr& wt) {
+            [](const Wall::Ptr& wt) {
                 return wt->role == Wall::Role::Program;
             }),
         texts.end());
@@ -105,7 +105,7 @@ ProgramSystem::run(TextWallList& texts, float world_scale)
 
 
 void
-ProgramSystem::update(TextWallList& texts, float world_scale)
+ProgramSystem::update(Wall::PtrList& texts, float world_scale)
 {
     if (_out_fd < 0) return;
 
@@ -167,19 +167,19 @@ ProgramSystem::feed_Input(const std::string& text)
 
 
 void
-ProgramSystem::echo_Input(TextWallList& texts, const std::string& line)
+ProgramSystem::echo_Input(Wall::PtrList& texts, const std::string& line)
 {
     push_Line(texts, line, World::get_BoxScale());   // scrolls up, lands at the prompt row
 }
 
 
 void
-ProgramSystem::echo_Words(TextWallList& texts, DynArray<Text3dPtr>& words, float world_scale)
+ProgramSystem::echo_Words(Wall::PtrList& texts, DynArray<Text3dPtr>& words, float world_scale)
 {
     if (words.empty()) return;
 
     // Make room: scroll existing program output up by one line.
-    for (TextWallPtr& wt : texts)
+    for (Wall::Ptr& wt : texts)
         if (wt->role == Wall::Role::Program)
             wt->text3d->pos.y += static_cast<double>(line_height);
 
@@ -194,8 +194,8 @@ ProgramSystem::echo_Words(TextWallList& texts, DynArray<Text3dPtr>& words, float
         w->pos.y = start_y;                 // align the echoed row to the line
         w->set_Look(ConfigColor::keep, Text3d::depth_wall);
 
-        texts.push_back(cpputils::make_unique<TextWall>(TextWall{
-            Wall::position_of(Wall::Role::Program),
+        texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
+            Wall::position_Of(Wall::Role::Program),
             Wall::Role::Program,
             std::move(w)
         }));
@@ -205,12 +205,12 @@ ProgramSystem::echo_Words(TextWallList& texts, DynArray<Text3dPtr>& words, float
 
 
 void
-ProgramSystem::push_Line(TextWallList& texts, const std::string& line, float world_scale)
+ProgramSystem::push_Line(Wall::PtrList& texts, const std::string& line, float world_scale)
 {
-    std::string clean = ascii_Sanitize(line);
+    std::string clean = Text::ascii_Sanitize(line);
 
     // Shift existing program-wall lines up so new output appears at the bottom.
-    for (TextWallPtr& wt : texts)
+    for (Wall::Ptr& wt : texts)
         if (wt->role == Wall::Role::Program)
             wt->text3d->pos.y += static_cast<double>(line_height);
 
@@ -223,7 +223,7 @@ ProgramSystem::push_Line(TextWallList& texts, const std::string& line, float wor
                               pos, ConfigColor::dark_gray);
     t->yaw = tf.yaw;
 
-    texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+    texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
         tf.wall_position,
         Wall::Role::Program,
         std::move(t)
diff --git a/src/systems/program_system.hpp b/src/systems/program_system.hpp
index 19e419a..8c436d9 100644
--- a/src/systems/program_system.hpp
+++ b/src/systems/program_system.hpp
@@ -1,10 +1,12 @@
 #pragma once
+
 #include <string>
 #include <sys/types.h>
 
 #include "entities/world.hpp"
 #include "utils/globals.hpp"
-#include "wall/text_wall.hpp"
+#include "wall/wall.hpp"
+
 
 struct ProgramSystem
 {
@@ -15,21 +17,21 @@ private:
 
     pid_t _child  {-1};
 
-    std::string _pending;       // partial-line buffer for stdout
+    std::string _pending;
 
-    void push_Line(TextWallList&, const std::string& line, float world_scale);
+    void push_Line  (Wall::PtrList&, const std::string& line, float world_scale);
     void close_Child();
 public:
     static inline float line_height = 0.4f;
     static inline float start_y     = World::get_FloorY() + 1;
 
-    void run        (TextWallList&, float world_scale);
-    void update     (TextWallList&, float world_scale);
+    void run        (Wall::PtrList&, float world_scale);
+    void update     (Wall::PtrList&, float world_scale);
+
     void feed_Input (const std::string& text);
-    void echo_Input (TextWallList&, const std::string& line);
-    // Park already-thrown (animated) words on the Program wall as one echoed
-    // input line, scrolling existing output up — terminal style.
-    void echo_Words (TextWallList&, DynArray<Text3dPtr>& words, float world_scale);
+    void echo_Input (Wall::PtrList&, const std::string& line);
+    void echo_Words (Wall::PtrList&, DynArray<Text3dPtr>& words, float world_scale);
+
     bool is_Running () const { return _child > 0; }
 
     ~ProgramSystem();
diff --git a/src/systems/projectile_system.cpp b/src/systems/projectile_system.cpp
index 89e2509..f4daef9 100644
--- a/src/systems/projectile_system.cpp
+++ b/src/systems/projectile_system.cpp
@@ -180,14 +180,14 @@ check_WallTextIntercept(const Projectile& p, const Vec3& centroid, double dt,
 
         if (editor_wall) {
             // Vertical row gate (as before): only the aimed row's words.
-            const double center_y = (wt.aabb_min.y + wt.aabb_max.y) * 0.5;
+            const double center_y = (wt.aabb_Min.y + wt.aabb_Max.y) * 0.5;
             if (SDL_fabs(aim_y - center_y) > ConfigWall::line_height * 0.5)
                 continue;
 
             // Horizontal: only shoot the word down if the aim lands in its
             // central 2/3. Outer 1/3 each side is "between words" → merge.
-            const double center_z = (wt.aabb_min.z + wt.aabb_max.z) * 0.5;
-            const double half_z   = (wt.aabb_max.z - wt.aabb_min.z) * 0.5;
+            const double center_z = (wt.aabb_Min.z + wt.aabb_Max.z) * 0.5;
+            const double half_z   = (wt.aabb_Max.z - wt.aabb_Min.z) * 0.5;
             if (SDL_fabs(aim_z - center_z) > half_z * (2.0 / 3.0))
                 continue;
 
@@ -197,12 +197,12 @@ check_WallTextIntercept(const Projectile& p, const Vec3& centroid, double dt,
             return true;
         }
 
-        Vec3 box_min { wt.aabb_min.x - word_he.x,
-                       wt.aabb_min.y - word_he.y,
-                       wt.aabb_min.z - word_he.z };
-        Vec3 box_max { wt.aabb_max.x + word_he.x,
-                       wt.aabb_max.y + word_he.y,
-                       wt.aabb_max.z + word_he.z };
+        Vec3 box_min { wt.aabb_Min.x - word_he.x,
+                       wt.aabb_Min.y - word_he.y,
+                       wt.aabb_Min.z - word_he.z };
+        Vec3 box_max { wt.aabb_Max.x + word_he.x,
+                       wt.aabb_Max.y + word_he.y,
+                       wt.aabb_Max.z + word_he.z };
 
         Collision::SweptResult sw =
             Collision::swept_RayAabb(p.prev_centroid, ray_dir, box_min, box_max);
@@ -353,12 +353,12 @@ handle_WallHit(Projectile& p, const Vec3& centroid, Wall::Position hit_pos,
                DynArray<ProjectileResult>& results,
                bool program_running)
 {
-    if (Wall::role_of(hit_pos) == Wall::Role::Program) {
+    if (Wall::role_Of(hit_pos) == Wall::Role::Program) {
         if (program_running) { begin_ProgramStick(p, ws); return false; }
         return bounce_OffWall(p, hit_pos, ws, results);
     }
 
-    const bool   editor = (Wall::role_of(hit_pos) == Wall::Role::Editor);
+    const bool   editor = (Wall::role_Of(hit_pos) == Wall::Role::Editor);
     const double plane  = wall_plane_coord(hit_pos, ws);
     const double aim_y  = editor ? editor_AimY(p, plane) : 0.0;
     const double aim_z  = editor ? editor_AimZ(p, plane) : 0.0;
@@ -377,7 +377,7 @@ handle_WallHit(Projectile& p, const Vec3& centroid, Wall::Position hit_pos,
         return true;
     }
 
-    if (Wall::role_of(hit_pos) == Wall::Role::Editor) {
+    if (Wall::role_Of(hit_pos) == Wall::Role::Editor) {
         begin_EditorStick(p, hit_pos);
         return false;
     }
diff --git a/src/systems/projectile_system.hpp b/src/systems/projectile_system.hpp
index cee9fc1..f1655c1 100644
--- a/src/systems/projectile_system.hpp
+++ b/src/systems/projectile_system.hpp
@@ -1,29 +1,40 @@
 #pragma once
 
-#include <cstdint>
-
 #include "systems/aim.hpp"
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
-#include "utils/math.hpp"
 #include "wall/wall.hpp"
 
+
 static constexpr uint8_t BOUNCED_X = 1 << 0;
 static constexpr uint8_t BOUNCED_Z = 1 << 1;
 
-struct Projectile {
+
+enum class ProjectileLanding : uint8_t
+{
+    None,
+    Floor,
+    ProgramInput,
+    Wall,
+    WallText,
+};
+
+
+struct Projectile
+{
     Wall::Position
          stick_wall    { Wall::Position::PosX };
     bool sticking      = false;
     bool collided      = false;
     bool program_stick = false;
-    uint8_t bounce_state  = 0;
+    uint8_t bounce_state = 0;
     float  ribbon_start_yaw  {};
     float  ribbon_target_yaw {};
     double yaw;
     double stick_t = 0.0;
     double step_dt = 0.0;
-    Text3d* track_obj    = nullptr;
+
+    Text3d* track_obj = nullptr;
 
     Vec3 vel{};
     Vec3 dir{};
@@ -42,36 +53,32 @@ struct Projectile {
     DynArray<Text3dPtr> words;
 };
 
-struct WallTextHitTest {
+
+struct WallTextHitTest
+{
     Wall::Position
            wall_position;
     size_t index;
 
-    Vec3 aabb_min;
-    Vec3 aabb_max;
+    Vec3 aabb_Min;
+    Vec3 aabb_Max;
 };
 
-enum class ProjectileLanding : uint8_t {
-    Floor,
-    None,
-    ProgramInput,
-    Wall,
-    WallText,
-};
 
-struct ProjectileResult {
+struct ProjectileResult
+{
     Wall::Position
-            wall_pos = Wall::Position::NegZ;
+           wall_pos        = Wall::Position::NegZ;
     size_t wall_text_index = 0;
-    Vec3   vel{};
+    Vec3   vel             {};
 
     ProjectileLanding   landing = ProjectileLanding::None;
     DynArray<Text3dPtr> words;
 };
 
 
-class ProjectileSystem {
-public:
+struct ProjectileSystem
+{
     void launch(DynArray<Projectile>& out,
                 DynArray<Text3dPtr> words,
                 const Vec3& fwd,
diff --git a/src/systems/pult_system.cpp b/src/systems/pult_system.cpp
index f7041c9..0683ac8 100644
--- a/src/systems/pult_system.cpp
+++ b/src/systems/pult_system.cpp
@@ -173,7 +173,7 @@ PultSystem::draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light
 
 
 DynArray<TextLabel*>
-PultSystem::get_Labels()
+PultSystem::get_Labels() const
 {
     DynArray<TextLabel*> out;
     out.reserve(_pults.size());
diff --git a/src/systems/pult_system.hpp b/src/systems/pult_system.hpp
index c899c71..1d23239 100644
--- a/src/systems/pult_system.hpp
+++ b/src/systems/pult_system.hpp
@@ -13,15 +13,21 @@ struct Light;
 struct Player;
 struct ProjectileContactEvent;
 
+
 class PultSystem
 {
+    Pult* _connect_program { nullptr };
+    Pult* _connect_editor  { nullptr };
+
     DynArray<Pult*> _pults;
-    Pult*           _connect_program { nullptr };
-    Pult*           _connect_editor  { nullptr };
 public:
-    void init                    (DynArray<GameObjectPtr>& scenery,
-                                  DynArray<PultButton*>&   buttons_out,
-                                  float                    world_scale);
+    void init        (DynArray<GameObjectPtr>& scenery,
+                      DynArray<PultButton*>&   buttons_out,
+                      float                    world_scale);
+    void update      (double dt, const Camera& camera);
+    void draw_Labels (GlRenderer& gl, const Camera& camera, const Light& light) const;
+
+
     std::optional<PultAction>
          try_Activate            (GameObject* obj,
                                   const DynArray<PultButton*>& buttons);
@@ -31,14 +37,11 @@ public:
     std::optional<PultAction>
          handle_PlayerContact    (const Player& player,
                                   const DynArray<PultButton*>& buttons);
+
     Vec3 get_ConnectProgramPos   () const;
     Vec3 get_ConnectEditorPos    () const;
-
     DynArray<TextLabel*>
-         get_Labels ();
-
-    void update     (double dt, const Camera& camera);
-    void draw_Labels(GlRenderer& gl, const Camera& camera, const Light& light) const;
+         get_Labels              () const;
 
 
 };
diff --git a/src/systems/wall_connection.cpp b/src/systems/wall_connection.cpp
index c44a937..0484c5a 100644
--- a/src/systems/wall_connection.cpp
+++ b/src/systems/wall_connection.cpp
@@ -1,5 +1,4 @@
 #include <SDL3/SDL.h>
-#include <cstdlib>
 #include <sstream>
 
 #include "cpp_token/cpp_highlight.hpp"
@@ -62,7 +61,7 @@ WallConnection::load_Editor(const DynArray<std::string>& lines, double eye_y)
     std::vector<std::string> v(lines.begin(), lines.end());
     _vim.load(v);
     if (_vim.is_Empty()) _vim.start_Insert();
-    _vim_seen_version = _vim.version();
+    _vim_seen_version = _vim.get_Version();
     _eye_y = eye_y;
     _status.clear();
     rebuild_Editor();
@@ -133,18 +132,18 @@ WallConnection::feed_Vim(DynArray<int>& keys, double eye_y)
         default: break;
     }
 
-    if (_vim.version() != _vim_seen_version) {
-        _vim_seen_version = _vim.version();
+    if (_vim.get_Version() != _vim_seen_version) {
+        _vim_seen_version = _vim.get_Version();
         rebuild_Editor();
     }
     return req;
 }
 
 DynArray<std::string>
-WallConnection::lines() const
+WallConnection::get_Lines() const
 {
     DynArray<std::string> out;
-    for (const std::string& l : _vim.lines()) out.push_back(l);
+    for (const std::string& l : _vim.get_Lines()) out.push_back(l);
     return out;
 }
 
@@ -155,15 +154,15 @@ WallConnection::rebuild_Editor()
     const float ws = World::get_BoxScale();
     Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, ws);
     const double lh    = ConfigWall::line_height;
-    const int    R     = _vim.row();
-    const int    N     = (int)_vim.lines().size();
+    const int    R     = _vim.get_Row();
+    const int    N     = (int)_vim.get_Lines().size();
     const double bottom_y = -static_cast<double>(ws) + 1.2;
 
     const double anchor_cursor = _eye_y + static_cast<double>(R) * lh;
     const double anchor_bottom = bottom_y + static_cast<double>(N - 1) * lh;
     _row0_y = SDL_min(anchor_cursor, anchor_bottom);
 
-    const auto& lines = _vim.lines();
+    const auto& lines = _vim.get_Lines();
 
     const double char_w = mono_CharWidth();
     const double he_y   = mono_HalfExtentY();
@@ -322,10 +321,10 @@ WallConnection::rebuild_Cmdline()
     _cmdline.reset();
 
     std::string text;
-    if      (_vim.mode() == VimBuffer::Mode::Command) text = _vim.cmdline();
-    else if (!_status.empty())                        text = _status[0];
-    else if (!_vim.status().empty())                  text = _vim.status();
-    else text = (_vim.mode() == VimBuffer::Mode::Insert) ? "-- INSERT --" : "-- NORMAL --";
+    if      (_vim.get_Mode() == VimBuffer::Mode::Command) text = _vim.get_Cmdline();
+    else if (!_status.empty())                            text = _status[0];
+    else if (!_vim.get_Status().empty())                  text = _vim.get_Status();
+    else text = (_vim.get_Mode() == VimBuffer::Mode::Insert) ? "-- INSERT --" : "-- NORMAL --";
     if (text.empty()) return;
 
     // Built at origin; render() places it at the eased _cmd_pos each frame.
@@ -336,7 +335,7 @@ WallConnection::rebuild_Cmdline()
 void
 WallConnection::update(double dt, const Camera& cam, float aspect, float fov_y)
 {
-    if (!active()) return;
+    if (!is_Active()) return;
     _blink += dt;
 
     const Vec3 up = Math::cross(cam.right, cam.fwd);
@@ -413,18 +412,18 @@ WallConnection::draw_ProgramCursor(GlRenderer& gl, const Camera& cam, const Ligh
     Vec3 c = _prog_input->pos;
     c.z    = _prog_input->pos.z - (static_cast<double>(_prog_input->half_extent) + 0.15);
 
-    Mat4 view  = buildViewMat4(cam);
-    Mat4 model = buildModelMat4(c, _prog_input->yaw);
-    Mat4 mvp   = Mat4::mul(gl.projection(), Mat4::mul(view, model));
+    Mat4 view      = buildViewMat4 (cam);
+    Mat4 get_Model = buildModelMat4(c, _prog_input->yaw);
+    Mat4 mvp       = Mat4::mul     (gl.get_Projection(), Mat4::mul(view, get_Model));
 
     gl.set_Wireframe(false);
-    gl.set_MVP(model, mvp);
-    gl.set_NormalMat(model);
-    gl.set_Light(light);
-    gl.set_Color(0.6f, 1.0f, 1.0f);
-    gl.set_Emissive(0.6f, 1.0f, 1.0f, 0.9f);
-    gl.draw_Box(0.04f, 0.22f, 0.02f);
-    gl.set_Emissive(0.0f, 0.0f, 0.0f, 0.0f);
+    gl.set_MVP      (get_Model, mvp);
+    gl.set_NormalMat(get_Model);
+    gl.set_Light    (light);
+    gl.set_Color    (0.6f,  1.0f,  1.0f);
+    gl.set_Emissive (0.6f,  1.0f,  1.0f, 0.9f);
+    gl.draw_Box     (0.04f, 0.22f, 0.02f);
+    gl.set_Emissive (0.0f,  0.0f,  0.0f, 0.0f);
 }
 
 void
@@ -432,7 +431,7 @@ WallConnection::draw_EditorCursor(GlRenderer& gl, const Camera& cam, const Light
 {
     if (SDL_fmod(_blink, 0.8) > 0.4) return;
 
-    const int row = _vim.row();
+    const int row = _vim.get_Row();
     if (row < 0 || row >= (int)_rows.size()) return;
 
     Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, World::get_BoxScale());
@@ -441,23 +440,23 @@ WallConnection::draw_EditorCursor(GlRenderer& gl, const Camera& cam, const Light
 
     const EditorRow& er = _rows[(size_t)row];
     const double cw     = er.char_w;
-    const int    col    = _vim.col();
+    const int    col    = _vim.get_Col();
     const double cz     = er.left_z - (static_cast<double>(col) + 0.5) * cw;
 
     Vec3 c { er.line_x, row_y - (er.he_y + 0.06), cz };
 
-    Mat4 view  = buildViewMat4(cam);
-    Mat4 model = buildModelMat4(c, tf.yaw);
-    Mat4 mvp   = Mat4::mul(gl.projection(), Mat4::mul(view, model));
+    Mat4 view      = buildViewMat4 (cam);
+    Mat4 get_Model = buildModelMat4(c, tf.yaw);
+    Mat4 mvp       = Mat4::mul     (gl.get_Projection(), Mat4::mul(view, get_Model));
 
     gl.set_Wireframe(false);
-    gl.set_MVP(model, mvp);
-    gl.set_NormalMat(model);
-    gl.set_Light(light);
-    gl.set_Color(0.6f, 1.0f, 1.0f);
-    gl.set_Emissive(0.6f, 1.0f, 1.0f, 0.9f);
-    gl.draw_Box(static_cast<float>(cw * 0.45), 0.015f, 0.03f);
-    gl.set_Emissive(0.0f, 0.0f, 0.0f, 0.0f);
+    gl.set_MVP      (get_Model, mvp);
+    gl.set_NormalMat(get_Model);
+    gl.set_Light    (light);
+    gl.set_Color    (0.6f, 1.0f, 1.0f);
+    gl.set_Emissive (0.6f, 1.0f, 1.0f, 0.9f);
+    gl.draw_Box     (static_cast<float>(cw * 0.45), 0.015f, 0.03f);
+    gl.set_Emissive (0.0f, 0.0f, 0.0f, 0.0f);
 }
 
 void
@@ -485,11 +484,11 @@ WallConnection::draw_Electric(GlRenderer& gl, const Camera& cam) const
     }
 
     Mat4 ident = Mat4::identity();
-    Mat4 mvp   = Mat4::mul(gl.projection(), buildViewMat4(cam));
-    gl.set_MVP(ident, mvp);
+    Mat4 mvp   = Mat4::mul(gl.get_Projection(), buildViewMat4(cam));
+    gl.set_MVP      (ident, mvp);
     gl.set_NormalMat(ident);
     gl.set_Wireframe(true);
-    gl.set_Color(0.5f, 0.9f, 1.0f);
-    gl.draw_Lines(pts.data(), static_cast<int>(pts.size()) / 3);
+    gl.set_Color    (0.5f, 0.9f, 1.0f);
+    gl.draw_Lines   (pts.data(), static_cast<int>(pts.size()) / 3);
     gl.set_Wireframe(false);
 }
diff --git a/src/systems/wall_connection.hpp b/src/systems/wall_connection.hpp
index 1c4487c..e1e760b 100644
--- a/src/systems/wall_connection.hpp
+++ b/src/systems/wall_connection.hpp
@@ -6,14 +6,17 @@
 #include "text_3d/text_3d.hpp"
 #include "text_3d/vim_buffer.hpp"
 #include "utils/globals.hpp"
-#include "utils/math.hpp"
+
 
 class Camera;
 class GlRenderer;
 struct Light;
 
-struct EditorRow {
-    DynArray<Text3dPtr> toks;     // per-token meshes, left→right (decreasing z)
+
+struct EditorRow
+{
+    DynArray<Text3dPtr>
+           toks;     // per-token meshes, left→right (decreasing z)
     double left_z   { 0.0 };      // z of the row's left edge (start of char 0)
     double char_w   { 0.18 };     // mean character width in z (for cursor placement)
     double he_y     { 0.2 };      // glyph half-height (for cursor vertical offset)
@@ -21,30 +24,34 @@ struct EditorRow {
     bool   has_text { false };
 };
 
+
 class WallConnection
 {
 public:
     enum class Target  : uint8_t { None, Program, Editor };
     enum class Request : uint8_t { None, Exit, Write, WriteQuit, QuitDiscard };
 
-    bool   active() const { return _target != Target::None; }
-    Target target() const { return _target; }
+    void    update(double dt, const Camera& cam, float aspect, float fov_y);
+    void    render(GlRenderer& gl, const Camera& cam, const Light& light) const;
+    void    end   ();
 
-    void begin_Program(const Vec3& pult_pos);
-    void begin_Editor (const Vec3& pult_pos, const DynArray<std::string>& lines, double eye_y);
-    void load_Editor  (const DynArray<std::string>& lines, double eye_y);
-    void end();
+    bool    is_Active () const { return _target != Target::None; }
 
-    void set_ProgramBuffer   (const std::string& buffer);
-    void clear_ProgramPreview();
+    Target  get_Target() const { return _target; }
+    DynArray<std::string>
+            get_Lines () const;
 
+    void    set_ProgramBuffer   (const std::string& buffer);
+
+    void    begin_Program(const Vec3& pult_pos);
+    void    begin_Editor (const Vec3& pult_pos, const DynArray<std::string>& lines, double eye_y);
+    void    load_Editor  (const DynArray<std::string>& lines, double eye_y);
+
+    void    mark_Saved() { _vim.mark_Saved(); }
+    void    clear_ProgramPreview();
     Request feed_Vim(DynArray<int>& keys, double eye_y);
-    DynArray<std::string>
-            lines   () const;
 
-    void update(double dt, const Camera& cam, float aspect, float fov_y);
-    void render(GlRenderer& gl, const Camera& cam, const Light& light) const;
-    void mark_Saved() { _vim.mark_Saved(); }
+
 
 private:
     bool     _cmd_pos_init { false };
diff --git a/src/systems/word_ai_system.hpp b/src/systems/word_ai_system.hpp
index a6de80f..b0d2033 100644
--- a/src/systems/word_ai_system.hpp
+++ b/src/systems/word_ai_system.hpp
@@ -3,23 +3,24 @@
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
 
-struct Player;
-struct CarriedLine;
 
-class WordAiSystem {
+struct CarriedLine;
+struct Player;
 
-    int   _max_active_ai = 5;
 
+class WordAiSystem
+{
+    int _max_active_ai = 5;
 
-    void update_Idle   (Text3d& w, const Player& p, int active_ai_count, double dt);
-    void update_Attack (Text3d& w, const Player& p, CarriedLine& carried,
-                        DynArray<Text3dPtr>& all_words,
-                        DynArray<Text3dPtr>& dropped,
-                        DynArray<Text3dPtr>& released,
-                        double dt);
-    void update_Flee   (Text3d& w, const Player& p,
-                        DynArray<Text3dPtr>& released, double dt);
-    void update_Stunned(Text3d& w, DynArray<Text3dPtr>& released, double dt);
+    void update_Idle  (Text3d& w, const Player& p, int active_ai_count, double dt);
+    void update_Attack(Text3d& w, const Player& p, CarriedLine& carried,
+                       DynArray<Text3dPtr>& all_words,
+                       DynArray<Text3dPtr>& dropped,
+                       DynArray<Text3dPtr>& released,
+                       double dt);
+    void update_Flee  (Text3d& w, const Player& p,
+                       DynArray<Text3dPtr>& released, double dt);
+    void update_Stunned    (Text3d& w, DynArray<Text3dPtr>& released, double dt);
     void update_StolenTrail(Text3d& w, double dt);
 
     void release_StolenWords(Text3d& w, DynArray<Text3dPtr>& out);
@@ -31,10 +32,11 @@ class WordAiSystem {
 
     void apply_Locomotion(Text3d& w, const Vec3& target_vel, double dt);
 public:
-    void set_MaxActiveAi (int n)    { _max_active_ai = n; }
-    void update(DynArray<Text3dPtr>& words,
-                const Player& player,
-                CarriedLine& carried,
-                DynArray<Text3dPtr>& dropped,
-                double dt);
+    void set_MaxActiveAi (int n) { _max_active_ai = n; }
+
+    void update (DynArray<Text3dPtr>& words,
+                 const Player& player,
+                 CarriedLine& carried,
+                 DynArray<Text3dPtr>& dropped,
+                 double dt);
 };
diff --git a/src/systems/word_anim.hpp b/src/systems/word_anim.hpp
index fa10fde..500ae93 100644
--- a/src/systems/word_anim.hpp
+++ b/src/systems/word_anim.hpp
@@ -4,13 +4,15 @@
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
 
-struct WordAnim_Add {
-    bool   complete{false};
+
+struct WordAnim_Add
+{
+    bool   complete     {false};
     double yaw_start;
     double yaw_target;
     double pitch_start  {0.0};
     double pitch_target {0.0};
-    double t{0.0};
+    double t            {0.0};
 
     Text3dPtr word;
 
@@ -18,14 +20,17 @@ struct WordAnim_Add {
     Vec3 target_pos;
 };
 
-struct WordAnim_Drop {
+
+struct WordAnim_Drop
+{
     bool complete{false};
 
     Text3dPtr word;
 };
 
-class WordAnimSystem {
-public:
+
+struct WordAnimSystem
+{
     void update(DynArray<WordAnim_Add>&  anims_add,
                 DynArray<WordAnim_Drop>& anims_drop,
                 CarriedLine&             carried,
diff --git a/src/text_3d/text_3d.cpp b/src/text_3d/text_3d.cpp
index b89b565..084e16d 100644
--- a/src/text_3d/text_3d.cpp
+++ b/src/text_3d/text_3d.cpp
@@ -81,7 +81,7 @@ 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)
+         depth(dpth), scale(scle), color(colr), text(txt)
 {
     set_Color(TokenColor::get(CppHighlight::classify_Word(text)));
 
@@ -124,7 +124,7 @@ Text3d::words_centroid(const DynArray<Text3dPtr>& words)
 
 
 Vec3
-Text3d::get_Distance(Vec3 position) {
+Text3d::get_Distance(Vec3 position) const {
     return pos - position;
 }
 
@@ -162,7 +162,7 @@ Text3d::set_Look(SDL_FColor c, float new_depth)
 void
 Text3d::rebuild_Mesh()
 {
-    loaded = buildTextMesh(mesh, font_path, text, 64, depth, scale);
+    loaded = mesh.build(font_path, text, 64, depth, scale);
     if (!loaded) {
         SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "Text3d: mesh build failed for \"%s\"", text.c_str());
         return;
@@ -227,14 +227,14 @@ Text3d::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
 {
     if (!loaded || packed_indices.empty()) return;
 
-    Mat4 proj  = gl.projection();
-    Mat4 view  = buildViewMat4(camera);
-    Mat4 model = buildModelMat4(pos, yaw, pitch);
-    Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
+    Mat4 proj  = gl.get_Projection();
+    Mat4 view  = buildViewMat4    (camera);
+    Mat4 model = buildModelMat4   (pos, yaw, pitch);
+    Mat4 mvp   = Mat4::mul        (proj, Mat4::mul(view, model));
 
     gl.set_Wireframe(false);
-    gl.set_Light(light);
-    gl.set_MVP(model, mvp);
+    gl.set_Light    (light);
+    gl.set_MVP      (model, mvp);
     gl.set_NormalMat(model);
     gl.set_FaceShade(color.r, color.g, color.b, back_dim, front_tint);
 
@@ -249,7 +249,7 @@ Text3d::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
                        packed_indices.data(), (int)packed_indices.size());
     gpu_dirty = false;
 
-    gl.set_Emissive(0.0f, 0.0f, 0.0f, 0.0f);
+    gl.set_Emissive (0.0f, 0.0f, 0.0f, 0.0f);
     gl.set_FaceShade(0.0f, 0.0f, 0.0f, 1.0f, false);
 
     // ── AI sparkle tail ──────────────────────────────────────────────────
@@ -331,15 +331,15 @@ Text3d::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
         }
 
         Mat4 ident = buildModelMat4(Vec3{0,0,0}, 0.0f, 0.0f);
-        gl.set_MVP(ident, Mat4::mul(proj, view));
+        gl.set_MVP      (ident, Mat4::mul(proj, view));
         gl.set_NormalMat(ident);
 
         const SDL_FColor glint = aiGlintColor(ai.state);
         for (int c = 0; c < PALN; ++c) {
             if (si[c].empty()) continue;
             SDL_FColor g = mix_col(PAL[c], glint, 0.15f);     // keep only a hint of state
-            gl.set_FaceShade(0.0f, 0.0f, 0.0f, 1.0f, false);  // no lit term → no white-out
-            gl.set_Emissive (g.r, g.g, g.b, 0.85f);           // pure colour, below clip
+            gl.set_FaceShade  (0.0f, 0.0f, 0.0f, 1.0f, false);  // no lit term → no white-out
+            gl.set_Emissive   (g.r, g.g, g.b, 0.85f);           // pure colour, below clip
             gl.draw_MeshCached(gpu_vbo_sparkle, gpu_ebo_sparkle,
                                gpu_sparkle_index_count, /*dirty=*/true,
                                sv[c].data(), (int)sv[c].size() / 9,
diff --git a/src/text_3d/text_3d.hpp b/src/text_3d/text_3d.hpp
index 9d85683..0ddb0ae 100644
--- a/src/text_3d/text_3d.hpp
+++ b/src/text_3d/text_3d.hpp
@@ -15,9 +15,11 @@
 class Camera;
 class GlRenderer;
 
+
 struct Text3dAI
 {
-    enum class State : uint8_t {
+    enum class State : uint8_t
+    {
         Idle,
         Attack,
         Flee,
@@ -42,70 +44,73 @@ struct Text3dAI
     Vec3 trail_dir {1.0, 0.0, 0.0};
 };
 
-struct Text3d final : public GameObject {
+
+struct Text3d final : public GameObject
+{
     static inline const std::string font_path =
         "/usr/share/fonts/dejavu/DejaVuSansMono.ttf";
 
-    Text3dAI ai;
-
-    float  glow_strength { 0.2f };
-    bool   glow_enabled  { false };
-    float  half_extent_y { 0.2f };
-
     static inline constexpr float depth_wall     = 0.06f;
     static inline constexpr float depth_floor    = 0.14f;
     static inline constexpr float depth_compiler = 0.02f;
     static Vec3 words_centroid(const DynArray<Text3dPtr>& words);
 
-    std::string text;
-    TextMesh    mesh;
-
-    // Cached GPU-ready data, rebuilt only in rebuild_Mesh().
-    DynArray<float> packed_verts;   // interleaved pos(3)|normal(3)|isfront(3)
-    DynArray<int>   packed_indices;
-    mutable unsigned int gpu_vbo { 0 };  // owned GL buffer; 0 = not yet uploaded
-    mutable unsigned int gpu_ebo { 0 };
-    mutable int          gpu_index_count { 0 };
     mutable bool         gpu_dirty { true };
+    mutable int          gpu_index_count { 0 };
+    mutable unsigned int gpu_vbo   { 0 };
+    mutable unsigned int gpu_ebo   { 0 };
 
-    // Sparkle overlay for AI words: a small star mesh rebuilt every frame.
     mutable unsigned int gpu_vbo_sparkle { 0 };
     mutable unsigned int gpu_ebo_sparkle { 0 };
     mutable int          gpu_sparkle_index_count { 0 };
 
-    // Tail: recent world positions, sampled over time (index 0 = newest).
     static constexpr int SPARKLE_TRAIL = 14;
-    mutable Vec3   sparkle_trail[SPARKLE_TRAIL];
     mutable int    sparkle_trail_count { 0 };
-    mutable Uint64 sparkle_last_ms { 0 };
+    mutable Uint64 sparkle_last_ms     { 0 };
+    mutable Vec3   sparkle_trail[SPARKLE_TRAIL];
+
 
+    bool  glow_enabled { false };
+    bool  loaded       { false };
+    bool  front_tint   { true };
 
-    bool       loaded{false};
-    SDL_FColor color;
-    float      back_dim   { 0.45f };
-    bool       front_tint { true };
-    float      depth;
-    float      scale;
-    float      half_extent{0.0f};
-    float      pitch{0.0f};
-    Vec3       ribbon_local{};
+    float glow_strength{ 0.2f };
+    float half_extent_y{ 0.2f };
+    float back_dim     { 0.45f };
+    float depth;
+    float scale;
+    float half_extent  { 0.0f };
+    float pitch        { 0.0f };
+
+    Vec3  ribbon_local {};
+
+    SDL_FColor  color;
+    std::string text;
+    TextMesh    mesh;
+    Text3dAI    ai;
+
+    DynArray<int>   packed_indices;
+    DynArray<float> packed_verts;
 
     Text3d(const std::string& txt,
            float depth, float scale,
-           Vec3 position,
+           Vec3  position,
            SDL_FColor colr = ConfigColor::blue);
     ~Text3d() override;
 
-    Vec3 get_Distance(Vec3 position);
-    void set_Color(SDL_FColor c);
-    void set_Depth(float depth);
-    void set_Look(SDL_FColor c, float depth);
+    Vec3 get_Distance(Vec3 position) const;
+    void set_Color   (SDL_FColor c);
+    void set_Depth   (float depth);
+    void set_Look    (SDL_FColor c, float depth);
     void rebuild_Mesh();
-    void update(const Vec3& camera_pos, const double view_mat[9], float carry_dist = 1.5f);
-    void draw(GlRenderer& gl, const Camera& camera, const Light& light) const override;
+    void update      (const Vec3& camera_pos, const double view_mat[9], float carry_dist = 1.5f);
+    void draw        (GlRenderer& gl, const Camera& camera, const Light& light) const override;
 };
 
+
 template<typename... Args>
-cpputils::unique_ptr<Text3d> make_Text3d(Args&&... args) {
+cpputils::unique_ptr<Text3d>
+make_Text3d(Args&&... args)
+{
     return cpputils::make_unique<Text3d>(std::forward<Args>(args)...);
 }
diff --git a/src/text_3d/text_file.hpp b/src/text_3d/text_file.hpp
deleted file mode 100644
index 21d2b93..0000000
--- a/src/text_3d/text_file.hpp
+++ /dev/null
@@ -1,84 +0,0 @@
-#pragma once
-
-#include <string>
-#include "cpp_token/cpp_highlight.hpp"   // HiSpan
-#include "cpp_token/token_color.hpp"     // TokenColor::get
-#include "text_3d/text_3d.hpp"
-#include "utils/globals.hpp"
-
-struct TextFile {
-    struct Token {
-        std::string text;
-        size_t      byte_begin { 0 };
-        size_t      byte_end   { 0 };
-        Text3d*     view       { nullptr };
-    };
-    struct Line {
-        DynArray<Token> tokens;
-    };
-
-    DynArray<Line> lines;
-
-    void clear() { lines.clear(); }
-
-    std::string render_Source()
-    {
-        std::string out;
-        for (Line& line : lines) {
-            for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
-                if (ti) out += ' ';
-                Token& tk = line.tokens[ti];
-                tk.byte_begin = out.size();
-                out += tk.text;
-                tk.byte_end = out.size();
-            }
-            out += '\n';
-        }
-        return out;
-    }
-
-    Token* token_At(size_t off)
-    {
-        for (Line& line : lines)
-            for (Token& tk : line.tokens)
-                if (off >= tk.byte_begin && off < tk.byte_end)
-                    return &tk;
-        return nullptr;
-    }
-
-    void apply_Spans(const DynArray<HiSpan>& spans)
-    {
-        for (Line& line : lines) {
-            for (Token& tk : line.tokens) {
-                if (!tk.view) continue;
-
-                size_t best_overlap = 0;
-                TokenType best_type = TokenType::Identifier;
-                bool found = false;
-                for (const HiSpan& s : spans) {
-                    size_t lo = (tk.byte_begin > s.byte_begin) ? tk.byte_begin : s.byte_begin;
-                    size_t hi = (tk.byte_end   < s.byte_end)   ? tk.byte_end   : s.byte_end;
-                    if (lo < hi) {
-                        size_t ov = hi - lo;
-                        if (ov > best_overlap) { best_overlap = ov; best_type = s.type; found = true; }
-                    }
-                }
-                if (found) tk.view->set_Color(TokenColor::get(best_type));
-            }
-        }
-    }
-
-    DynArray<std::string> as_Lines() const
-    {
-        DynArray<std::string> out;
-        for (const Line& line : lines) {
-            std::string s;
-            for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
-                if (ti) s += ' ';
-                s += line.tokens[ti].text;
-            }
-            out.push_back(s);
-        }
-        return out;
-    }
-};
diff --git a/src/text_3d/text_label.cpp b/src/text_3d/text_label.cpp
index 69f23ef..4e2b2eb 100644
--- a/src/text_3d/text_label.cpp
+++ b/src/text_3d/text_label.cpp
@@ -142,7 +142,7 @@ TextLabel::rebuild(const std::string& text)
 
 
 Vec3
-TextLabel::current_Centre() const
+TextLabel::get_CurrentCentre() const
 {
     if (_mode == PositionMode::Anchor && _anchor_ptr) {
         return {
@@ -160,7 +160,7 @@ TextLabel::update(double dt, const Camera& camera)
 {
     if (_words.empty()) return;
 
-    Vec3  centre           = current_Centre();
+    Vec3  centre           = get_CurrentCentre();
     Vec3  right            {1, 0, 0};
     float yaw_for_glyphs   = 0.0f;
     float pitch_for_glyphs = 0.0f;
diff --git a/src/text_3d/text_label.hpp b/src/text_3d/text_label.hpp
index 1f14ef1..1a83f94 100644
--- a/src/text_3d/text_label.hpp
+++ b/src/text_3d/text_label.hpp
@@ -7,10 +7,14 @@
 #include "utils/globals.hpp"
 #include "utils/light.hpp"
 
+
 class GlRenderer;
 
-class TextLabel {
-    enum class PositionMode : uint8_t {
+
+class TextLabel
+{
+    enum class PositionMode : uint8_t
+    {
         Absolute,
         Anchor,
     };
@@ -39,27 +43,29 @@ class TextLabel {
 
 
     void rebuild(const std::string& text);
-    Vec3 current_Centre() const;
+    Vec3 get_CurrentCentre() const;
 
 public:
     TextLabel() = default;
 
+    void clear         ();
+    void update        (double dt, const Camera& camera);
+    void draw          (GlRenderer& gl, const Camera& camera, const Light& light) const;
+    void kick          (size_t word_index, const Vec3& projectile_vel, const Vec3& normal);
+
     void attach_To     (const Vec3* anchor, const Vec3& offset = {});
     void detach        ();
 
     void set_Centre    (const Vec3& p);
     void set_Billboard (bool on) { _billboard = on; }
-    void set_FaceYaw   (float y)  { _face_yaw = y;  }
+    void set_FaceYaw   (float y) { _face_yaw = y;   }
     void set_Style     (SDL_FColor color, float depth, float scale);
     void set_Collidable(bool on);
     void set_Text      (const std::string& text);
     void set_Text      (const std::string& text,
                         SDL_FColor color, float depth, float scale);
-    void clear         ();
-    void update        (double dt, const Camera& camera);
-    void draw          (GlRenderer& gl, const Camera& camera, const Light& light) const;
-    void kick          (size_t word_index, const Vec3& projectile_vel, const Vec3& normal);
-    bool empty         () const { return _words.empty(); }
+
+    bool is_Empty      () const { return _words.empty(); }
     const DynArray<Text3dPtr>&
-         words         () const { return _words; }
+         get_Words     () const { return _words; }
 };
diff --git a/src/text_3d/text_mesh.cpp b/src/text_3d/text_mesh.cpp
index a3d8373..364ff32 100644
--- a/src/text_3d/text_mesh.cpp
+++ b/src/text_3d/text_mesh.cpp
@@ -203,13 +203,14 @@ void computeVertexNormals(TextMesh& mesh)
     }
 }
 
-bool buildTextMesh(TextMesh& out, const std::string& font_path,
-                   const std::string& text, int size, float depth, float scale)
+bool
+TextMesh::build(const std::string& font_path,
+                const std::string& text, int size, float depth, float scale)
 {
-    out.verts   .clear();
-    out.tris    .clear();
-    out.is_front.clear();
-    //out.edges.clear();
+    verts   .clear();
+    tris    .clear();
+    is_front.clear();
+    //edges.clear();
 
     FT_Library ft;
     if (FT_Init_FreeType(&ft)) { SDL_LogError(SDL_LOG_CATEGORY_APPLICATION, "FT_Init_FreeType failed"); return false; }
@@ -251,34 +252,34 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
                 for (auto& p : ring)
                     flat.push_back(p);
 
-            int base      = static_cast<int>(out.verts.size());
+            int base      = static_cast<int>(verts.size());
             float half_d  = depth * 0.5f;
 
             // Front verts (z = -half_d, facing -Z = toward viewer)
             for (auto& p : flat) {
-                out.verts.push_back({ static_cast<double>(p[0]),
+                verts.push_back({ static_cast<double>(p[0]),
                                       static_cast<double>(p[1]),
                                       static_cast<double>(-half_d) });
-                out.is_front.push_back(1.0f);
+                is_front.push_back(1.0f);
             }
-            int back_base = static_cast<int>(out.verts.size());
+            int back_base = static_cast<int>(verts.size());
             // Back verts (z = +half_d)
             for (auto& p : flat) {
-                out.verts.push_back({ static_cast<double>(p[0]),
+                verts.push_back({ static_cast<double>(p[0]),
                                       static_cast<double>(p[1]),
                                       static_cast<double>( half_d) });
-                out.is_front.push_back(0.0f);
+                is_front.push_back(0.0f);
             }
 
             // Front face triangles
             for (size_t i = 0; i+2 < indices.size(); i += 3) {
-                out.tris.push_back({ base + static_cast<int>(indices[i]  ),
+                tris.push_back({ base + static_cast<int>(indices[i]  ),
                                      base + static_cast<int>(indices[i+2]),
                                      base + static_cast<int>(indices[i+1]) });
             }
             // Back face triangles — natural winding so normal faces -Z.
             for (size_t i = 0; i+2 < indices.size(); i += 3)
-                out.tris.push_back({ back_base + static_cast<int>(indices[i]  ),
+                tris.push_back({ back_base + static_cast<int>(indices[i]  ),
                                      back_base + static_cast<int>(indices[i+1]),
                                      back_base + static_cast<int>(indices[i+2]) });
 
@@ -291,30 +292,30 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
                     int i1 = (i + 1) % rn;
 
                     // 4 unique verts per quad — no sharing with face verts
-                    int wb = static_cast<int>(out.verts.size());
+                    int wb = static_cast<int>(verts.size());
 
                     const Pt2& p0 = ring[static_cast<size_t>(i)];
                     const Pt2& p1 = ring[static_cast<size_t>(i1)];
 
-                    out.verts.push_back({ static_cast<double>(p0[0]),
+                    verts.push_back({ static_cast<double>(p0[0]),
                             static_cast<double>(p0[1]),
                             static_cast<double>(-half_d) }); // front-left
-                    out.is_front.push_back(0.0f);
-                    out.verts.push_back({ static_cast<double>(p1[0]),
+                    is_front.push_back(0.0f);
+                    verts.push_back({ static_cast<double>(p1[0]),
                             static_cast<double>(p1[1]),
                             static_cast<double>(-half_d) }); // front-right
-                    out.is_front.push_back(0.0f);
-                    out.verts.push_back({ static_cast<double>(p1[0]),
+                    is_front.push_back(0.0f);
+                    verts.push_back({ static_cast<double>(p1[0]),
                             static_cast<double>(p1[1]),
                             static_cast<double>( half_d) }); // back-right
-                    out.is_front.push_back(0.0f);
-                    out.verts.push_back({ static_cast<double>(p0[0]),
+                    is_front.push_back(0.0f);
+                    verts.push_back({ static_cast<double>(p0[0]),
                             static_cast<double>(p0[1]),
                             static_cast<double>( half_d) }); // back-left
-                    out.is_front.push_back(0.0f);
+                    is_front.push_back(0.0f);
 
-                    out.tris.push_back({ wb+0, wb+1, wb+2 });
-                    out.tris.push_back({ wb+0, wb+2, wb+3 });
+                    tris.push_back({ wb+0, wb+1, wb+2 });
+                    tris.push_back({ wb+0, wb+2, wb+3 });
                 }
                 ring_offset_flat += rn;
             }
@@ -327,10 +328,10 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
     FT_Done_FreeType(ft);
 
     // Centre mesh on bounding box
-    if (!out.verts.empty()) {
+    if (!verts.empty()) {
         float minX=1e9f, maxX=-1e9f;
 
-        for (const Vec3& v : out.verts) {
+        for (const Vec3& v : verts) {
             float vx = static_cast<float>(v.x);
             if (vx < minX) minX = vx;
             if (vx > maxX) maxX = vx;
@@ -338,12 +339,12 @@ bool buildTextMesh(TextMesh& out, const std::string& font_path,
 
         double cx = static_cast<double>((minX + maxX) * 0.5f);
 
-        for (Vec3& v : out.verts) {
+        for (Vec3& v : verts) {
             v.x -= cx;
         }
     }
 
-    computeVertexNormals(out);
+    computeVertexNormals(*this);
 
-    return !out.verts.empty();
+    return !verts.empty();
 }
diff --git a/src/text_3d/text_mesh.hpp b/src/text_3d/text_mesh.hpp
index 5107bf9..e8d3663 100644
--- a/src/text_3d/text_mesh.hpp
+++ b/src/text_3d/text_mesh.hpp
@@ -3,28 +3,34 @@
 #include <string>
 
 #include "utils/globals.hpp"
-#include "utils/math.hpp"
 
-struct Vertex {
+
+struct Vertex
+{
     Vec3 pos;
     Vec3 normal;
 };
 
-struct MeshTri { int a, b, c; };
 
-struct TextMesh {
+struct MeshTri
+{ int a, b, c; };
+
+
+struct TextMesh
+{
     DynArray<Vec3>    verts;
     DynArray<MeshTri> tris;
     DynArray<Vec3>    vertex_normals;
     DynArray<float>   is_front;
+
+    bool build(
+        const std::string& font_path,
+        const std::string& text,
+        int                size  = 64,
+        float              depth = 0.4f,
+        float              scale = 0.003f
+    );
 };
 
-bool buildTextMesh(
-    TextMesh&          out,
-    const std::string& font_path,
-    const std::string& text,
-    int                size  = 64,
-    float              depth = 0.4f,
-    float              scale = 0.003f
-);
+
 
diff --git a/src/text_3d/vim_buffer.cpp b/src/text_3d/vim_buffer.cpp
new file mode 100644
index 0000000..3c0fa79
--- /dev/null
+++ b/src/text_3d/vim_buffer.cpp
@@ -0,0 +1,228 @@
+#include "vim_buffer.hpp"
+
+
+void
+VimBuffer::load(const std::vector<std::string>& src)
+{
+    _lines = src;
+    if (_lines.empty()) _lines.push_back("");
+    _row   = _col = 0; _mode = Mode::Normal;
+    _count = 0;
+    _sig   = Signal::None; ++_version;
+    _saved = _lines;
+    _dirty = false;
+
+    _pending.clear();
+    _cmd    .clear();
+    _status .clear();
+}
+
+
+void
+VimBuffer::key_char(char c)
+{
+    if      (_mode == Mode::Insert)  { insert_Char(c); }
+    else if (_mode == Mode::Command) { _cmd.push_back(c); touch(); }
+    else                             { normal_Key(c); }
+}
+
+void
+VimBuffer::key_enter()
+{
+    if      (_mode == Mode::Insert)  { split_Line(); }
+    else if (_mode == Mode::Command) { run_Command(); }
+    else                             { _row = get_ClampRow(_row + 1); clamp_Col(); touch(); }
+}
+
+void VimBuffer::key_backspace()
+{
+    if      (_mode == Mode::Insert)  { backspace_Insert(); }
+    else if (_mode == Mode::Command) { if (_cmd.size() > 1) _cmd.pop_back(); else cancel_Command(); touch(); }
+    else                             { _col = (_col > 0 ? _col - 1 : 0); touch(); }
+}
+
+void VimBuffer::key_escape()
+{
+    if (_mode == Mode::Command) { cancel_Command(); return; }
+    _mode = Mode::Normal;
+    if (_col > 0) --_col;
+    clamp_Col(); touch();
+}
+
+
+VimBuffer::Signal
+VimBuffer::take_Signal()
+{ Signal s = _sig; _sig = Signal::None; return s; }
+
+
+void
+VimBuffer::mark_Saved()
+{ _saved = _lines; _dirty = false; touch(); }
+
+
+void
+VimBuffer::touch()
+{ ++_version; }
+
+int 
+VimBuffer::get_LineLen() const
+{ return (int)_lines[(size_t)_row].size(); }
+
+int
+VimBuffer::get_ClampRow(int r) const
+{ int n=(int)_lines.size(); return r<0?0:(r>=n?n-1:r); }
+
+void
+VimBuffer::clamp_Col()
+{
+    int maxc = (_mode==Mode::Insert) ? get_LineLen() : (get_LineLen()>0 ? get_LineLen()-1 : 0);
+    if (_col < 0) _col = 0;
+    if (_col > maxc) _col = maxc;
+}
+
+int
+VimBuffer::get_Eff() const
+{ return _count > 0 ? _count : 1; }
+
+void
+VimBuffer::normal_Key(char c)
+{
+    if (c == ':') { _mode = Mode::Command; _cmd = ":"; 
+                    _status.clear(); touch(); return; }
+
+    if (std::isdigit((unsigned char)c)) {
+        if (c == '0' && _count == 0 && _pending.empty())
+                { _col = 0; touch(); return; }
+        _count = _count * 10 + (c - '0'); return;
+    }
+
+    if (_pending == "d") { _pending.clear();
+        if (c == 'd') { delete_Lines(get_Eff()); _count = 0;
+                        touch(); return; }
+        _count = 0; return;
+    }
+    if (_pending == "g") { _pending.clear();
+        if (c == 'g') { _row = get_ClampRow(_count > 0 ? _count - 1 : 0);
+                        _count = 0; clamp_Col(); touch(); return; }
+        _count = 0; return;
+    }
+
+    switch (c) {
+        case 'h': _col -= get_Eff();                            break;
+        case 'l': _col += get_Eff();                            break;
+        case 'j': _row = get_ClampRow(_row + get_Eff());        break;
+        case 'k': _row = get_ClampRow(_row - get_Eff());        break;
+        case '0': _col = 0;                                     break;
+        case '$': _col = get_LineLen() > 0 ? get_LineLen() - 1 : 0;                    break;
+        case 'x': delete_Chars(get_Eff());                      break;
+        case 'i': _mode = Mode::Insert;                         break;
+        case 'a': _col = (get_LineLen() > 0 ? _col + 1 : 0); _mode = Mode::Insert;     break;
+        case 'A': _col = get_LineLen(); _mode = Mode::Insert;   break;
+        case 'o': open_Below(); _mode = Mode::Insert;           break;
+        case 'O': open_Above(); _mode = Mode::Insert;           break;
+        case 'G': _row = get_ClampRow(_count > 0 ? _count - 1 : (int)_lines.size() - 1);break;
+        case 'd': _pending = "d";                               return;
+        case 'g': _pending = "g";                               return;
+        default: break;
+    }
+    _count = 0; clamp_Col(); touch();
+}
+
+void
+VimBuffer::insert_Char(char c)
+{
+    std::string& L = _lines[(size_t)_row];
+    if (_col > (int)L.size()) _col = (int)L.size();
+    L.insert((size_t)_col, 1, c); ++_col; _dirty = true; touch();
+}
+
+void
+VimBuffer::split_Line()
+{
+    std::string& L = _lines[(size_t)_row];
+    std::string tail = L.substr((size_t)_col);
+    L.erase((size_t)_col);
+    _lines.insert(_lines.begin() + _row + 1, tail);
+    ++_row; _col = 0; _dirty = true; touch();
+}
+
+void
+VimBuffer::backspace_Insert()
+{
+    if (_col > 0) { _lines[(size_t)_row].erase((size_t)(_col-1), 1); --_col; _dirty = true; }
+    else if (_row > 0) {
+        int prevlen = (int)_lines[(size_t)(_row-1)].size();
+        _lines[(size_t)(_row-1)] += _lines[(size_t)_row];
+        _lines.erase(_lines.begin() + _row);
+        --_row; _col = prevlen; _dirty = true;
+    }
+    touch();
+}
+
+void
+VimBuffer::delete_Chars(int n)
+{
+    std::string& L = _lines[(size_t)_row];
+    for (int i = 0; i < n && _col < (int)L.size(); ++i) { L.erase((size_t)_col, 1); _dirty = true; }
+    clamp_Col();
+}
+
+void
+VimBuffer::delete_Lines(int n)
+{
+    for (int i = 0; i < n && (int)_lines.size() > 0; ++i) {
+        if (_lines.size() == 1) { _lines[0].clear(); _dirty = true; break; }
+        _lines.erase(_lines.begin() + _row);
+        if (_row >= (int)_lines.size()) _row = (int)_lines.size() - 1;
+        _dirty = true;
+    }
+    clamp_Col();
+}
+void
+VimBuffer::open_Below()
+{ _lines.insert(_lines.begin() + _row + 1, ""); ++_row; _col = 0; _dirty = true; }
+
+void
+VimBuffer::open_Above()
+{ _lines.insert(_lines.begin() + _row,     ""); _col = 0; _dirty = true; }
+
+void
+VimBuffer::run_Command()
+{
+    std::string c = _cmd.size() ? _cmd.substr(1) : "";
+    _cmd.clear(); _mode = Mode::Normal;
+
+    if (c == "w" || c == "write") {
+        _sig = Signal::Write;
+    }
+    else if (c == "wq" || c == "x") {
+        _sig = Signal::WriteQuit;
+    }
+    else if (c == "q" || c == "quit") {
+        if (_dirty) {
+            _status = "No write since last change (add ! to override)";
+        } else {
+            _sig = Signal::Exit;
+        }
+    }
+    else if (c == "q!" || c == "quit!") {
+        _lines = _saved;
+        _row = get_ClampRow(_row); clamp_Col();
+        _dirty = false;
+        _sig = Signal::QuitDiscard;
+    }
+    else if (!c.empty() && std::all_of(c.begin(), c.end(),
+             [](char ch){ return std::isdigit((unsigned char)ch); })) {
+        _row = get_ClampRow(std::stoi(c) - 1); clamp_Col();
+    }
+    else _status = "not a command: " + c;
+    touch();
+}
+
+void
+VimBuffer::cancel_Command()
+{ _cmd.clear(); _mode = Mode::Normal; touch(); }
+
+bool
+VimBuffer::is_Dirty() const
+{ return _dirty; }
diff --git a/src/text_3d/vim_buffer.hpp b/src/text_3d/vim_buffer.hpp
index a9dd8d2..c70fdb3 100644
--- a/src/text_3d/vim_buffer.hpp
+++ b/src/text_3d/vim_buffer.hpp
@@ -8,7 +8,7 @@
 class VimBuffer {
 public:
     enum class Mode   : uint8_t { Normal, Insert, Command };
-        enum class Signal : uint8_t {
+    enum class Signal : uint8_t {
         None,
         Exit,
         Help,
@@ -17,51 +17,29 @@ public:
         QuitDiscard
     };
 
-    void load(const std::vector<std::string>& src) {
-        _lines = src;
-        if (_lines.empty()) _lines.push_back("");
-        _row = _col = 0; _mode = Mode::Normal;
-        _count = 0; _pending.clear(); _cmd.clear(); _status.clear();
-        _sig = Signal::None; ++_version;
-        _saved = _lines;
-        _dirty = false;
-    }
+    void key_char     (char c);
+    void key_enter    ();
+    void key_backspace();
+    void key_escape   ();
 
+    void   load       (const std::vector<std::string>& src);
+    Signal take_Signal();
+    void   mark_Saved ();
 
-    void key_char(char c) {
-        if      (_mode == Mode::Insert)  { insert_Char(c); }
-        else if (_mode == Mode::Command) { _cmd.push_back(c); touch(); }
-        else                             { normal_Key(c); }
-    }
-    void key_enter() {
-        if      (_mode == Mode::Insert)  { split_Line(); }
-        else if (_mode == Mode::Command) { run_Command(); }
-        else                             { _row = clampRow(_row + 1); clampCol(); touch(); }
-    }
-    void key_backspace() {
-        if      (_mode == Mode::Insert)  { backspace_Insert(); }
-        else if (_mode == Mode::Command) { if (_cmd.size() > 1) _cmd.pop_back(); else cancel_Command(); touch(); }
-        else                             { _col = (_col > 0 ? _col - 1 : 0); touch(); }
-    }
-    void key_escape() {
-        if (_mode == Mode::Command) { cancel_Command(); return; }
-        _mode = Mode::Normal;
-        if (_col > 0) --_col;
-        clampCol(); touch();
-    }
+    bool is_Empty() const { return _lines.size() == 1 && _lines[0].empty(); }
 
     const std::vector<std::string>&
-                       lines()    const { return _lines; }
-    int                row()      const { return _row; }
-    int                col()      const { return _col; }
-    Mode               mode()     const { return _mode; }
-    unsigned           version()  const { return _version; }
-    bool               is_Empty() const { return _lines.size() == 1 && _lines[0].empty(); }
-    void               start_Insert()   { _mode = Mode::Insert; _col = 0; touch(); }
-    const std::string& cmdline()  const { return _cmd; }
-    const std::string& status()   const { return _status; }
-    Signal take_Signal() { Signal s = _sig; _sig = Signal::None; return s; }
-    void mark_Saved() { _saved = _lines; _dirty = false; touch(); }
+         get_Lines   () const { return _lines; }
+    int  get_Row     () const { return _row; }
+    int  get_Col     () const { return _col; }
+    Mode get_Mode    () const { return _mode; }
+    unsigned
+         get_Version () const { return _version; }
+    const std::string&
+         get_Cmdline () const { return _cmd; }
+    const std::string&
+         get_Status  () const { return _status; }
+    void start_Insert() { _mode = Mode::Insert; _col = 0; touch(); }
 
 private:
     bool     _dirty = false;
@@ -76,128 +54,23 @@ private:
     Mode     _mode = Mode::Normal;
     Signal   _sig = Signal::None;
     std::vector<std::string> _saved;
-    std::vector<std::string> _lines { "" };
-
-    void touch() { ++_version; }
-    int  lineLen() const { return (int)_lines[(size_t)_row].size(); }
-    int  clampRow(int r) const { int n=(int)_lines.size(); return r<0?0:(r>=n?n-1:r); }
-    void clampCol() {
-        int maxc = (_mode==Mode::Insert) ? lineLen() : (lineLen()>0 ? lineLen()-1 : 0);
-        if (_col < 0) _col = 0;
-        if (_col > maxc) _col = maxc;
-    }
-    int  eff() const { return _count > 0 ? _count : 1; }
-
-    void normal_Key(char c) {
-        if (c == ':') { _mode = Mode::Command; _cmd = ":"; _status.clear(); touch(); return; }
-
-        if (std::isdigit((unsigned char)c)) {
-            if (c == '0' && _count == 0 && _pending.empty())
-                    { _col = 0; touch(); return; }
-            _count = _count * 10 + (c - '0'); return;
-        }
-
-        if (_pending == "d") { _pending.clear();
-            if (c == 'd') { delete_Lines(eff()); _count = 0; touch(); return; }
-            _count = 0; return;
-        }
-        if (_pending == "g") { _pending.clear();
-            if (c == 'g') { _row = clampRow(_count > 0 ? _count - 1 : 0); _count = 0; clampCol(); touch(); return; }
-            _count = 0; return;
-        }
-
-        switch (c) {
-            case 'h': _col -= eff();                 break;
-            case 'l': _col += eff();                 break;
-            case 'j': _row = clampRow(_row + eff()); break;
-            case 'k': _row = clampRow(_row - eff()); break;
-            case '0': _col = 0;                      break;
-            case '$': _col = lineLen() > 0 ? lineLen() - 1 : 0; break;
-            case 'x': delete_Chars(eff());           break;
-            case 'i': _mode = Mode::Insert;          break;
-            case 'a': _col = (lineLen() > 0 ? _col + 1 : 0); _mode = Mode::Insert;      break;
-            case 'A': _col = lineLen(); _mode = Mode::Insert;   break;
-            case 'o': open_Below(); _mode = Mode::Insert;       break;
-            case 'O': open_Above(); _mode = Mode::Insert;       break;
-            case 'G': _row = clampRow(_count > 0 ? _count - 1 : (int)_lines.size() - 1);break;
-            case 'd': _pending = "d";                return;
-            case 'g': _pending = "g";                return;
-            default: break;
-        }
-        _count = 0; clampCol(); touch();
-    }
-
-    void insert_Char(char c) {
-        std::string& L = _lines[(size_t)_row];
-        if (_col > (int)L.size()) _col = (int)L.size();
-        L.insert((size_t)_col, 1, c); ++_col; _dirty = true; touch();
-    }
-    void split_Line() {
-        std::string& L = _lines[(size_t)_row];
-        std::string tail = L.substr((size_t)_col);
-        L.erase((size_t)_col);
-        _lines.insert(_lines.begin() + _row + 1, tail);
-        ++_row; _col = 0; _dirty = true; touch();
-    }
-    void backspace_Insert() {
-        if (_col > 0) { _lines[(size_t)_row].erase((size_t)(_col-1), 1); --_col; _dirty = true; }
-        else if (_row > 0) {
-            int prevlen = (int)_lines[(size_t)(_row-1)].size();
-            _lines[(size_t)(_row-1)] += _lines[(size_t)_row];
-            _lines.erase(_lines.begin() + _row);
-            --_row; _col = prevlen; _dirty = true;
-        }
-        touch();
-    }
-    void delete_Chars(int n) {
-        std::string& L = _lines[(size_t)_row];
-        for (int i = 0; i < n && _col < (int)L.size(); ++i) { L.erase((size_t)_col, 1); _dirty = true; }
-        clampCol();
-    }
-    void delete_Lines(int n) {
-        for (int i = 0; i < n && (int)_lines.size() > 0; ++i) {
-            if (_lines.size() == 1) { _lines[0].clear(); _dirty = true; break; }
-            _lines.erase(_lines.begin() + _row);
-            if (_row >= (int)_lines.size()) _row = (int)_lines.size() - 1;
-            _dirty = true;
-        }
-        clampCol();
-    }
-    void open_Below() { _lines.insert(_lines.begin() + _row + 1, ""); ++_row; _col = 0; _dirty = true; }
-    void open_Above() { _lines.insert(_lines.begin() + _row,     ""); _col = 0; _dirty = true; }
-
-    void run_Command() {
-        std::string c = _cmd.size() ? _cmd.substr(1) : "";
-        _cmd.clear(); _mode = Mode::Normal;
-
-        if (c == "w" || c == "write") {
-            _sig = Signal::Write;
-        }
-        else if (c == "wq" || c == "x") {
-            _sig = Signal::WriteQuit;
-        }
-        else if (c == "q" || c == "quit") {
-            if (_dirty) {
-                _status = "No write since last change (add ! to override)";
-            } else {
-                _sig = Signal::Exit;
-            }
-        }
-        else if (c == "q!" || c == "quit!") {
-            _lines = _saved;
-            _row = clampRow(_row); clampCol();
-            _dirty = false;
-            _sig = Signal::QuitDiscard;
-        }
-        else if (!c.empty() && std::all_of(c.begin(), c.end(),
-                 [](char ch){ return std::isdigit((unsigned char)ch); })) {
-            _row = clampRow(std::stoi(c) - 1); clampCol();
-        }
-        else _status = "not a command: " + c;
-        touch();
-    }
-    void cancel_Command() { _cmd.clear(); _mode = Mode::Normal; touch(); }
-
-    bool dirty() const { return _dirty; }
-
+    std::vector<std::string> _lines{ "" };
+
+    void touch           ();
+    void clamp_Col       ();
+    void normal_Key      (char c);
+    void insert_Char     (char c);
+    void split_Line      ();
+    void backspace_Insert();
+    void delete_Chars    (int n);
+    void delete_Lines    (int n);
+    void open_Below      ();
+    void open_Above      ();
+    void run_Command     ();
+    void cancel_Command  ();
+
+    bool is_Dirty        ()      const;
+    int  get_LineLen     ()      const;
+    int  get_Eff         ()      const;
+    int  get_ClampRow    (int r) const;
 };
diff --git a/src/utils/ascii.hpp b/src/utils/ascii.hpp
deleted file mode 100644
index 86c4bdc..0000000
--- a/src/utils/ascii.hpp
+++ /dev/null
@@ -1,53 +0,0 @@
-#pragma once
-#include <string>
-
-// ─────────────────────────────────────────────────────────────────────────
-// ascii_Sanitize — collapse non-ASCII bytes to safe ASCII for wall display.
-//
-// gcc diagnostics use Unicode directional quotes (U+2018/2019 ‘ ’, U+201C/201D
-// “ ”) which the text renderer can't draw. This maps the common ones to plain
-// ' and ", and replaces any other multibyte sequence with '?'. Used by both
-// CompilerSystem and DynLoaderSystem so their wall output stays renderable.
-//
-// Note: also set LC_ALL=C on the gcc invocation to make gcc emit ASCII quotes
-// at the source; this function is the belt-and-suspenders fallback.
-// ─────────────────────────────────────────────────────────────────────────
-inline std::string
-ascii_Sanitize(const std::string& in)
-{
-    std::string out;
-    out.reserve(in.size());
-
-    size_t i = 0;
-    while (i < in.size()) {
-        const unsigned char c = static_cast<unsigned char>(in[i]);
-
-        if (c < 0x80) {
-            out += static_cast<char>(c);
-            ++i;
-            continue;
-        }
-
-        // U+2000–U+20FF punctuation block: E2 80 xx
-        if (c == 0xE2 && i + 2 < in.size() &&
-            static_cast<unsigned char>(in[i + 1]) == 0x80) {
-            const unsigned char c3 = static_cast<unsigned char>(in[i + 2]);
-            switch (c3) {
-                case 0x98: case 0x99: out += '\''; break;  // ‘ ’
-                case 0x9C: case 0x9D: out += '"';  break;  // “ ”
-                case 0x93: case 0x94: out += '-';  break;  // – —
-                default:              out += '\''; break;
-            }
-            i += 3;
-            continue;
-        }
-
-        // Any other multibyte sequence: one '?', skip continuation bytes.
-        out += '?';
-        ++i;
-        while (i < in.size() &&
-               (static_cast<unsigned char>(in[i]) & 0xC0) == 0x80)
-            ++i;
-    }
-    return out;
-}
diff --git a/src/utils/carry_math.cpp b/src/utils/carry_math.cpp
index ddbe43f..a247648 100644
--- a/src/utils/carry_math.cpp
+++ b/src/utils/carry_math.cpp
@@ -1,10 +1,11 @@
+#include <SDL3/SDL.h>
+
 #include "carry_math.hpp"
 #include "entities/camera.hpp"
-#include <SDL3/SDL.h>
 
 
 Vec3
-CarryMath::line_Anchor(const Camera& camera, double carry_dist)
+CarryMath::get_LineAnchor(const Camera& camera, double carry_dist)
 {
     const Vec3& right = camera.right;
     const Vec3  up    = Math::cross(camera.right, camera.fwd);
@@ -21,10 +22,10 @@ CarryMath::line_Anchor(const Camera& camera, double carry_dist)
 
 
 DynArray<Vec3>
-CarryMath::slot_Positions(const CarriedLine& carried,
-                          const Vec3& anchor,
-                          const Vec3& right,
-                          double carry_gap)
+CarryMath::get_SlotPosition(const CarriedLine& carried,
+                            const Vec3& anchor,
+                            const Vec3& right,
+                            double carry_gap)
 {
     DynArray<Vec3> positions;
     DynArray<CarriedWordNode*> nodes = carried.reverse_nodes();
diff --git a/src/utils/carry_math.hpp b/src/utils/carry_math.hpp
index 2fb88c9..c11f35e 100644
--- a/src/utils/carry_math.hpp
+++ b/src/utils/carry_math.hpp
@@ -1,13 +1,12 @@
 #pragma once
 
-#include <cstdint>
-
 #include "systems/carry_system.hpp"
 #include "utils/globals.hpp"
-#include "utils/math.hpp"
+
 
 class Camera;
 
+
 namespace CarryMath
 {
     static constexpr double CARRY_DIST = 1.2;
@@ -17,10 +16,10 @@ namespace CarryMath
     static constexpr double CARRY_HAND_DOWN  = 0.35;
 
 
-    Vec3 line_Anchor(const Camera& camera, double carry_dist);
+    Vec3 get_LineAnchor   (const Camera& camera, double carry_dist);
     DynArray<Vec3>
-         slot_Positions(const CarriedLine& carried,
-                        const Vec3& anchor,
-                        const Vec3& right,
-                        double carry_gap);
+         get_SlotPosition(const CarriedLine& carried,
+                          const Vec3& anchor,
+                          const Vec3& right,
+                          double carry_gap);
 }
diff --git a/src/utils/config.hpp b/src/utils/config.hpp
index 07604b0..448f276 100644
--- a/src/utils/config.hpp
+++ b/src/utils/config.hpp
@@ -23,7 +23,7 @@ static constexpr double player_move_accel    = 60.0;
 
 static constexpr double proj_gravity     = 9.0;
 static constexpr double proj_throw_speed = 18.0;
-static constexpr double proj_t_min       = 0.18;  // clamp: nearest throws
+static constexpr double proj_t_min       = 0.18;  // clamp: nearest  throws
 static constexpr double proj_t_max       = 1.2;   // clamp: farthest throws
 }
 
diff --git a/src/utils/frame_profiler.hpp b/src/utils/frame_profiler.hpp
index 8ef699e..9a8274a 100644
--- a/src/utils/frame_profiler.hpp
+++ b/src/utils/frame_profiler.hpp
@@ -36,15 +36,20 @@
 #else
 
 
-namespace fp {
+namespace fp
+{
 
-inline double perf_to_ms(Uint64 ticks) {
+inline double
+perf_to_ms(Uint64 ticks)
+{
     static const double inv_freq_ms =
         1000.0 / static_cast<double>(SDL_GetPerformanceFrequency());
     return static_cast<double>(ticks) * inv_freq_ms;
 }
 
-struct Zone {
+
+struct Zone
+{
     const char* name      {nullptr};
     uint32_t    calls     {0};      // calls across the report window
     Uint64      total     {0};      // accumulated ticks across the report window
@@ -52,7 +57,9 @@ struct Zone {
     Uint64      peak      {0};      // peak per-frame ticks in window
 };
 
-struct Frame {
+
+struct Frame
+{
     static constexpr size_t MAX_ZONES = 32;
     bool     started        {false};
     size_t   num_zones      {0};
@@ -63,7 +70,7 @@ struct Frame {
 
     std::array<Zone, MAX_ZONES> zones{};
 
-    Zone* find_or_add(const char* name) {
+    Zone* find_OrAdd(const char* name) {
         // Pointer-equality lookup — string literals dedupe naturally.
         for (size_t i = 0; i < num_zones; ++i)
             if (zones[i].name == name) return &zones[i];
@@ -72,7 +79,7 @@ struct Frame {
         return &zones[num_zones++];
     }
 
-    void begin_frame() {
+    void begin_Frame() {
         if (!started) {
             window_start = SDL_GetPerformanceCounter();
             started      = true;
@@ -80,7 +87,7 @@ struct Frame {
         for (size_t i = 0; i < num_zones; ++i) zones[i].frame_sum = 0;
     }
 
-    void end_frame() {
+    void end_Frame() {
         ++frames_in_win;
         for (size_t i = 0; i < num_zones; ++i) {
             Zone& z = zones[i];
@@ -92,7 +99,7 @@ struct Frame {
         Uint64 elapsed_ticks = now - window_start;
         double elapsed_ms = perf_to_ms(elapsed_ticks);
         if (elapsed_ms >= 1000.0) {
-            print_report(elapsed_ms);
+            print_Report(elapsed_ms);
             // reset window
             for (size_t i = 0; i < num_zones; ++i) {
                 zones[i].total = 0;
@@ -104,7 +111,7 @@ struct Frame {
         }
     }
 
-    void print_report(double elapsed_ms) const {
+    void print_Report(double elapsed_ms) const {
         // Sort indices by total descending — don't reorder the zone array
         // itself, names are stable pointers and we rely on order persistence.
         std::array<size_t, MAX_ZONES> order{};
@@ -146,7 +153,7 @@ struct ScopedZone {
     Zone*  zone;
     Uint64 t0;
     ScopedZone(const char* name)
-        : zone(frame().find_or_add(name))
+        : zone(frame().find_OrAdd(name))
         , t0(zone ? SDL_GetPerformanceCounter() : 0) {}
     ~ScopedZone() {
         if (!zone) return;
@@ -163,7 +170,7 @@ struct ScopedZone {
 #define FP_CONCAT(a,b)  FP_CONCAT_(a,b)
 #define FP_ZONE(name)   ::fp::ScopedZone FP_CONCAT(_fp_zone_, __LINE__){name}
 
-#define FRAME_BEGIN()   ::fp::frame().begin_frame()
-#define FRAME_END()     ::fp::frame().end_frame()
+#define FRAME_BEGIN()   ::fp::frame().begin_Frame()
+#define FRAME_END()     ::fp::frame().end_Frame()
 
 #endif // !FRAME_PROFILER_DISABLED
diff --git a/src/utils/globals.hpp b/src/utils/globals.hpp
index b32df99..ed1d089 100644
--- a/src/utils/globals.hpp
+++ b/src/utils/globals.hpp
@@ -1,25 +1,25 @@
 #pragma once
 
-#include "math.hpp"
 #include <SDL3/SDL.h>
 #include <memory>
 #include <print>
 #include <vector>
-#include <cpputils/unique_ptr.hpp>
+
+#include "cpputils/unique_ptr.hpp"
+#include "math.hpp"
 
 
 class  GlRenderer;
-struct Text3d;
-struct TextWall;
-struct GameObject;
 struct CarriedWordNode;
+struct GameObject;
+struct Text3d;
+
+using Math::Vec3;
 
 template<typename T> 
 using DynArray           = std::vector<T>;
 
 using GlRendererPtr      = cpputils::unique_ptr<GlRenderer>;
 using Text3dPtr          = cpputils::unique_ptr<Text3d>;
-using TextWallPtr        = cpputils::unique_ptr<TextWall>;
-using TextWallList       = DynArray<TextWallPtr>;
 using CarriedWordNodePtr = cpputils::unique_ptr<CarriedWordNode>;
 using GameObjectPtr      = cpputils::unique_ptr<GameObject>;
diff --git a/src/utils/light.hpp b/src/utils/light.hpp
index d436bd8..570513b 100644
--- a/src/utils/light.hpp
+++ b/src/utils/light.hpp
@@ -2,41 +2,17 @@
 
 #include "math.hpp"
 
-// ─────────────────────────────────────────────────────────────────────────
-// Light
-//
-// Three components:
-//
-//   1. Sun — directional, fixed in world. `direction` is the direction
-//      LIGHT TRAVELS (sun overhead → direction points downward).
-//      Illumination at surface = max(dot(N, -direction), 0).
-//      sun_intensity is 0 by default: the scene is lit entirely by the
-//      flashlight and ambient. Raise it if you add an outdoor area.
-//
-//   2. Ambient — uniform fill, adds to every fragment.
-//
-//   3. Flashlight — positional + cone. Player carries it.
-//      `flashlight_pos` is the beam origin (camera/head). `flashlight_dir`
-//      is the unit vector the beam shines along (where the camera looks).
-//      Cone has a smooth falloff between inner_cos and outer_cos.
-//      Both must be updated per frame from the camera before set_Light().
-// ─────────────────────────────────────────────────────────────────────────
 struct Light {
-    // ── Sun ─────────────────────────────────────────────────────────────
-    Vec3  direction     { 0.3, -0.9, 0.2 };
+    Vec3  sun_direction { 0.3, -0.9, 0.2 };
     Vec3  sun_color     { 1.00, 0.95, 0.85 };
-    float sun_intensity { 0.0f };   // 0 = sun disabled; scene uses flashlight only
+    float sun_intensity { 0.0f }; // off for now
 
-    // ── Ambient ─────────────────────────────────────────────────────────
     Vec3  ambient { 0.25, 0.27, 0.30 };
 
-    // ── Flashlight (player's beam) ──────────────────────────────────────
-    Vec3  flashlight_pos       { 0.0, 0.0, 0.0 };    // set per-frame from camera
-    Vec3  flashlight_dir       { 0.0, 0.0, -1.0 };   // unit vec; set per-frame from camera
-    Vec3  flashlight_color     { 1.00, 0.95, 0.80 }; // warm white
+    Vec3  flashlight_pos       { 0.0, 0.0, 0.0 };
+    Vec3  flashlight_dir       { 0.0, 0.0, -1.0 };
+    Vec3  flashlight_color     { 1.00, 0.95, 0.80 };
     float flashlight_range     { 40.0f };
-    // Cone falloff: full brightness inside inner_cos, smooth fade to zero at outer_cos.
-    // Both are cosines of the half-angle from the beam axis (1=on-axis, 0=perpendicular).
     float flashlight_inner_cos { 0.85f };  // ≈ 32° full cone
     float flashlight_outer_cos { 0.50f };  // ≈ 60° cutoff
     float flashlight_intensity { 1.5f };
@@ -44,14 +20,14 @@ struct Light {
     Light() { normalize(); }
 
     void normalize() {
-        double len = std::sqrt(direction.x*direction.x +
-                               direction.y*direction.y +
-                               direction.z*direction.z);
-        if (len > 1e-6) direction = direction / len;
+        double len = SDL_sqrt(sun_direction.x*sun_direction.x +
+                              sun_direction.y*sun_direction.y +
+                              sun_direction.z*sun_direction.z);
+        if (len > 1e-6) sun_direction = sun_direction / len;
 
-        len = std::sqrt(flashlight_dir.x*flashlight_dir.x +
-                        flashlight_dir.y*flashlight_dir.y +
-                        flashlight_dir.z*flashlight_dir.z);
+        len = SDL_sqrt(flashlight_dir.x*flashlight_dir.x +
+                       flashlight_dir.y*flashlight_dir.y +
+                       flashlight_dir.z*flashlight_dir.z);
         if (len > 1e-6) flashlight_dir = flashlight_dir / len;
     }
 };
diff --git a/src/utils/math.hpp b/src/utils/math.hpp
index 4171cb9..4adbae8 100644
--- a/src/utils/math.hpp
+++ b/src/utils/math.hpp
@@ -1,15 +1,21 @@
 #pragma once
 
+#include <SDL3/SDL_stdinc.h>
 #include <random>
 
 
-namespace Random {
-inline int int_MinMax(int min, int max) {
+namespace Random
+{
+
+inline int
+int_MinMax(int min, int max)
+{
     std::mt19937 rng(std::random_device{}());
     std::uniform_int_distribution<int> dist(min, max);
     return dist(rng);
 }
 
+
 inline double
 unit()
 {
@@ -17,10 +23,16 @@ unit()
     static std::uniform_real_distribution<double> dist(0.0, 1.0);
     return dist(rng);
 }
+
 } // Rendom
 
 
-struct Vec3 {
+namespace Math
+{
+
+
+struct Vec3
+{
     double x{}, y{}, z{};
 
     Vec3() = default;
@@ -41,9 +53,6 @@ inline Vec3 operator-(Vec3 a, const Vec3& b) { return a -= b; }
 inline Vec3 operator*(Vec3 v, double s)      { return v *= s; }
 inline Vec3 operator/(Vec3 v, double s)      { return v /= s; }
 
-namespace Math
-{
-
 inline double
 dot(const Vec3& a, const Vec3& b)
 { return a.x*b.x + a.y*b.y + a.z*b.z; }
@@ -64,7 +73,7 @@ length_sq(const Vec3& v)
 
 inline double
 length(const Vec3& v)
-{ return std::sqrt(length_sq(v)); }
+{ return SDL_sqrt(length_sq(v)); }
 
 inline Vec3
 normalize(const Vec3& v)
diff --git a/src/utils/text.cpp b/src/utils/text.cpp
new file mode 100644
index 0000000..aba7de4
--- /dev/null
+++ b/src/utils/text.cpp
@@ -0,0 +1,165 @@
+#include "text.hpp"
+
+
+namespace Text
+{
+
+DynArray<std::string>
+wrap_String(const std::string& text, size_t max_chars)
+{
+    std::string word;
+    std::string current_line;
+
+    DynArray<std::string> lines;
+
+    auto flush_line = [&]() {
+        while (!current_line.empty() && current_line.back() == ' ')
+            current_line.pop_back();
+        lines.push_back(current_line);
+        current_line.clear();
+    };
+
+    auto flush_word = [&]() {
+        if (word.empty()) return;
+        if (current_line.size() + word.size() + (current_line.empty() ? 0 : 1)
+                > max_chars) {
+            flush_line();
+        }
+        if (!current_line.empty()) current_line += ' ';
+        current_line += word;
+        word.clear();
+    };
+
+    for (char c : text) {
+        if (c == '\n') {
+            flush_word();
+            flush_line();
+        }
+        else if (c == ' ' || c == '\t') {
+            flush_word();
+        }
+        else {
+            word += c;
+        }
+    }
+    flush_word();
+    flush_line();
+
+    return lines;
+}
+
+std::string
+ascii_Sanitize(const std::string& in)
+{
+    std::string out;
+    out.reserve(in.size());
+
+    size_t i = 0;
+    while (i < in.size()) {
+        const unsigned char c = static_cast<unsigned char>(in[i]);
+
+        if (c < 0x80) {
+            out += static_cast<char>(c);
+            ++i;
+            continue;
+        }
+
+        // U+2000–U+20FF punctuation block: E2 80 xx
+        if (c == 0xE2 && i + 2 < in.size() &&
+            static_cast<unsigned char>(in[i + 1]) == 0x80) {
+            const unsigned char c3 = static_cast<unsigned char>(in[i + 2]);
+            switch (c3) {
+                case 0x98: case 0x99: out += '\''; break;  // ‘ ’
+                case 0x9C: case 0x9D: out += '"';  break;  // “ ”
+                case 0x93: case 0x94: out += '-';  break;  // – —
+                default:              out += '\''; break;
+            }
+            i += 3;
+            continue;
+        }
+
+        // Any other multibyte sequence: one '?', skip continuation bytes.
+        out += '?';
+        ++i;
+        while (i < in.size() &&
+               (static_cast<unsigned char>(in[i]) & 0xC0) == 0x80)
+            ++i;
+    }
+    return out;
+}
+
+
+
+void
+View::clear()
+{ lines.clear(); }
+
+
+std::string
+View::render_Source()
+{
+    std::string out;
+    for (Line& line : lines) {
+        for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
+            if (ti) out += ' ';
+            Token& tk = line.tokens[ti];
+            tk.byte_begin = out.size();
+            out += tk.text;
+            tk.byte_end = out.size();
+        }
+        out += '\n';
+    }
+    return out;
+}
+
+
+Token*
+View::token_At(size_t off)
+{
+    for (Line& line : lines)
+        for (Token& tk : line.tokens)
+            if (off >= tk.byte_begin && off < tk.byte_end)
+                return &tk;
+    return nullptr;
+}
+
+
+void
+View::apply_Spans(const DynArray<HiSpan>& spans)
+{
+    for (Line& line : lines) {
+        for (Token& tk : line.tokens) {
+            if (!tk.view) continue;
+
+            size_t best_overlap = 0;
+            TokenType best_type = TokenType::Identifier;
+            bool found = false;
+            for (const HiSpan& s : spans) {
+                size_t lo = (tk.byte_begin > s.byte_begin) ? tk.byte_begin : s.byte_begin;
+                size_t hi = (tk.byte_end   < s.byte_end)   ? tk.byte_end   : s.byte_end;
+                if (lo < hi) {
+                    size_t ov = hi - lo;
+                    if (ov > best_overlap) { best_overlap = ov; best_type = s.type; found = true; }
+                }
+            }
+            if (found) tk.view->set_Color(TokenColor::get(best_type));
+        }
+    }
+}
+
+DynArray<std::string>
+View::as_Lines() const
+{
+    DynArray<std::string> out;
+    for (const Line& line : lines) {
+        std::string s;
+        for (size_t ti = 0; ti < line.tokens.size(); ++ti) {
+            if (ti) s += ' ';
+            s += line.tokens[ti].text;
+        }
+        out.push_back(s);
+    }
+    return out;
+}
+
+} // namespace Text
diff --git a/src/utils/text.hpp b/src/utils/text.hpp
new file mode 100644
index 0000000..57e0522
--- /dev/null
+++ b/src/utils/text.hpp
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <string>
+
+#include "cpp_token/cpp_highlight.hpp"
+#include "cpp_token/token_color.hpp"
+#include "text_3d/text_3d.hpp"
+#include "utils/globals.hpp"
+
+
+namespace Text
+{
+
+DynArray<std::string>
+    wrap_String(const std::string& text, size_t max_chars);
+
+std::string
+    ascii_Sanitize(const std::string& in);
+
+
+
+struct Token
+{
+    std::string text;
+    size_t      byte_begin { 0 };
+    size_t      byte_end   { 0 };
+    Text3d*     view       { nullptr };
+};
+
+
+struct Line
+{
+    DynArray<Token> tokens;
+};
+
+struct View
+{
+
+    DynArray<Line> lines;
+
+    void        clear        ();
+    std::string render_Source();
+    Token*      token_At     (size_t off);
+    void        apply_Spans  (const DynArray<HiSpan>& spans);
+    DynArray<std::string>
+                as_Lines     () const;
+};
+
+} // namespace Text
diff --git a/src/utils/text_wrap.hpp b/src/utils/text_wrap.hpp
deleted file mode 100644
index e75c9d8..0000000
--- a/src/utils/text_wrap.hpp
+++ /dev/null
@@ -1,59 +0,0 @@
-#pragma once
-
-#include <string>
-
-#include "utils/globals.hpp"
-
-// ─────────────────────────────────────────────────────────────────────────
-// wrap_Text — break `text` into lines no longer than `max_chars`.
-//
-// Rules (matching the infowall behavior it was extracted from):
-//   - explicit '\n' forces a line break (and can produce an empty line)
-//   - spaces/tabs separate words; a word that would overflow the current
-//     line starts a new line instead of being split
-//   - trailing spaces are trimmed from each line
-//   - a single word longer than max_chars is NOT split — it occupies its
-//     own (over-length) line, same as the original
-// ─────────────────────────────────────────────────────────────────────────
-inline DynArray<std::string>
-wrap_Text(const std::string& text, size_t max_chars)
-{
-    DynArray<std::string> lines;
-    std::string current_line;
-    std::string word;
-
-    auto flush_line = [&]() {
-        while (!current_line.empty() && current_line.back() == ' ')
-            current_line.pop_back();
-        lines.push_back(current_line);   // may be empty (blank line)
-        current_line.clear();
-    };
-
-    auto flush_word = [&]() {
-        if (word.empty()) return;
-        if (current_line.size() + word.size() + (current_line.empty() ? 0 : 1)
-                > max_chars) {
-            flush_line();
-        }
-        if (!current_line.empty()) current_line += ' ';
-        current_line += word;
-        word.clear();
-    };
-
-    for (char c : text) {
-        if (c == '\n') {
-            flush_word();
-            flush_line();
-        }
-        else if (c == ' ' || c == '\t') {
-            flush_word();
-        }
-        else {
-            word += c;
-        }
-    }
-    flush_word();
-    flush_line();
-
-    return lines;
-}
diff --git a/src/wall/editor_wall.cpp b/src/wall/editor.cpp
similarity index 91%
rename from src/wall/editor_wall.cpp
rename to src/wall/editor.cpp
index 9017def..4d4db46 100644
--- a/src/wall/editor_wall.cpp
+++ b/src/wall/editor.cpp
@@ -2,21 +2,24 @@
 #include <algorithm>
 #include <string>
 
-#include "editor_wall.hpp"
+#include "editor.hpp"
 #include "entities/camera.hpp"
 #include "entities/world.hpp"
 #include "rendering/gl_renderer.hpp"
 
 
+namespace Wall
+{
+
 void
-EditorWall::clear()
+Editor::clear()
 {
     _lines.clear();
 }
 
 
-EditorWall::Line*
-EditorWall::find_NearestLine(double y)
+Editor::Line*
+Editor::find_NearestLine(double y)
 {
     Line*  best    = nullptr;
     double best_dy = ConfigWall::snap_threshold_y;
@@ -30,8 +33,8 @@ EditorWall::find_NearestLine(double y)
 }
 
 
-EditorWall::Target
-EditorWall::resolve_Target(double y) const
+Editor::Target
+Editor::resolve_Target(double y) const
 {
     DynArray<size_t> order;
     for (size_t i = 0; i < _lines.size(); ++i)
@@ -114,8 +117,8 @@ EditorWall::resolve_Target(double y) const
 }
 
 
-EditorWall::Line&
-EditorWall::apply_Target(const Target& t)
+Editor::Line&
+Editor::apply_Target(const Target& t)
 {
     if (t.kind == Target::Merge)
         return _lines[t.line_index];
@@ -137,8 +140,8 @@ EditorWall::apply_Target(const Target& t)
 }
 
 
-EditorWall::Placement
-EditorWall::place_OnLine(Line& line, double new_half_z, double impact_z)
+Editor::Placement
+Editor::place_OnLine(Line& line, double new_half_z, double impact_z)
 {
     if (line.words.empty())
         return { 0, impact_z };
@@ -187,7 +190,7 @@ EditorWall::place_OnLine(Line& line, double new_half_z, double impact_z)
 
 
 void
-EditorWall::on_LinePlaced(const DynArray<Text3d*>& words_in, const Vec3& impact)
+Editor::on_LinePlaced(const DynArray<Text3d*>& words_in, const Vec3& impact)
 {
     if (words_in.empty()) return;
 
@@ -263,7 +266,7 @@ EditorWall::on_LinePlaced(const DynArray<Text3d*>& words_in, const Vec3& impact)
 
 
 void
-EditorWall::on_WordRemoved(Text3d* word)
+Editor::on_WordRemoved(Text3d* word)
 {
     if (!word) return;
 
@@ -284,7 +287,7 @@ EditorWall::on_WordRemoved(Text3d* word)
 
 
 Vec3
-EditorWall::on_WordPlaced(Text3d* word, const Vec3& impact_pos)
+Editor::on_WordPlaced(Text3d* word, const Vec3& impact_pos)
 {
     if (!word) return impact_pos;
 
@@ -305,7 +308,7 @@ EditorWall::on_WordPlaced(Text3d* word, const Vec3& impact_pos)
 
 
 void
-EditorWall::add_PlacedLine(const DynArray<Text3d*>& words, double row_y)
+Editor::add_PlacedLine(const DynArray<Text3d*>& words, double row_y)
 {
     if (words.empty()) return;
     Line line;
@@ -348,7 +351,7 @@ set_NumberText(Text3d* t, const std::string& s)
 
 
 void
-EditorWall::update(double dt, const Vec3& eye_pos)
+Editor::update(double dt, const Vec3& eye_pos)
 {
     if (_lines.empty()) return;
 
@@ -361,7 +364,7 @@ EditorWall::update(double dt, const Vec3& eye_pos)
     std::sort(order.begin(), order.end(),
         [&](size_t a, size_t b){ return _lines[a].y > _lines[b].y; });
 
-    const Wall::Transform tf = Wall::get_Transform(Wall::Role::Editor, World::get_BoxScale());
+    const Transform tf = get_Transform(Role::Editor, World::get_BoxScale());
 
     if (order.empty()) return;
 
@@ -372,8 +375,8 @@ EditorWall::update(double dt, const Vec3& eye_pos)
     for (size_t oi : order)
         for (Text3d* w : _lines[oi].words) {
             if (!w) continue;
-            code_left  = std::max(code_left,  w->pos.z + (double)w->half_extent);
-            code_right = std::min(code_right, w->pos.z - (double)w->half_extent);
+            code_left  = SDL_max(code_left,  w->pos.z + (double)w->half_extent);
+            code_right = SDL_min(code_right, w->pos.z - (double)w->half_extent);
         }
 
     // Pass 1: ensure labels exist, refresh digits, advance the bounce, and find
@@ -398,8 +401,8 @@ EditorWall::update(double dt, const Vec3& eye_pos)
         l.bounce_vel += (-STIFFNESS * l.bounce_off - DAMPING * l.bounce_vel) * dt;
         l.bounce_off += l.bounce_vel * dt;
 
-        max_lh = std::max(max_lh, (double)l.num_left->half_extent);
-        max_rh = std::max(max_rh, (double)l.num_right->half_extent);
+        max_lh = SDL_max(max_lh, static_cast<double>(l.num_left ->half_extent));
+        max_rh = SDL_max(max_rh, static_cast<double>(l.num_right->half_extent));
         ++rank;
     }
 
@@ -411,8 +414,8 @@ EditorWall::update(double dt, const Vec3& eye_pos)
     const double EDGE = 0.3;
     double left_col_z  = code_left  + ConfigWall::line_number_gap;
     double right_col_z = code_right - ConfigWall::line_number_gap;
-    left_col_z  = std::min(left_col_z,   ws - EDGE - 2.0 * max_lh);
-    right_col_z = std::max(right_col_z, -ws + EDGE + 2.0 * max_rh);
+    left_col_z  = SDL_min(left_col_z,   ws - EDGE - 2.0 * max_lh);
+    right_col_z = SDL_max(right_col_z, -ws + EDGE + 2.0 * max_rh);
 
     // Pass 2: place each number against its column at its (bounced) row height.
     for (size_t oi : order) {
@@ -424,19 +427,19 @@ EditorWall::update(double dt, const Vec3& eye_pos)
         for (Text3d* w : l.words) { if (w) { x = w->pos.x; break; } }
 
         const double ny = l.y + l.bounce_off;
-        const double lh = (double)l.num_left->half_extent;
-        const double rh = (double)l.num_right->half_extent;
+        const double lh = static_cast<double>(l.num_left-> half_extent);
+        const double rh = static_cast<double>(l.num_right->half_extent);
         l.num_left->pos  = Vec3{ x, ny, left_col_z  + lh };   // code-facing edge on the column
         l.num_right->pos = Vec3{ x, ny, right_col_z - rh };
 
-        l.num_left->pitch  = Wall::tilt_TowardEye(l.num_left->pos,  eye_pos);
-        l.num_right->pitch = Wall::tilt_TowardEye(l.num_right->pos, eye_pos);
+        l.num_left->pitch  = Text::tilt_TowardEye(l.num_left->pos,  eye_pos);
+        l.num_right->pitch = Text::tilt_TowardEye(l.num_right->pos, eye_pos);
     }
 }
 
 
 DynArray<DynArray<Text3d*>>
-EditorWall::lines_InOrder() const
+Editor::lines_InOrder() const
 {
     // Order rows top→bottom (largest y first), matching update()'s numbering.
     DynArray<size_t> order;
@@ -463,8 +466,8 @@ EditorWall::lines_InOrder() const
 }
 
 
-DynArray<EditorWall::NumberHit>
-EditorWall::number_Hitboxes() const
+DynArray<Editor::NumberHit>
+Editor::number_Hitboxes() const
 {
     // Build the box live from the label's current pos + half-extents rather
     // than the base aabb_*() (which can lag a constantly-repositioned object).
@@ -476,8 +479,8 @@ EditorWall::number_Hitboxes() const
     out.reserve(_lines.size() * 2);
 
     auto push_box = [&](const Text3d* t, size_t i) {
-        const double hz = (double)t->half_extent   + PAD;   // along wall (z)
-        const double hy = (double)t->half_extent_y + PAD;   // vertical
+        const double hz = static_cast<double>(t->half_extent  ) + PAD;   // along wall (z)
+        const double hy = static_cast<double>(t->half_extent_y) + PAD;   // vertical
         const Vec3   c  = t->pos;
         out.push_back({ HIT_BASE + i,
                         Vec3{ c.x - DEPTH_X, c.y - hy, c.z - hz },
@@ -494,7 +497,7 @@ EditorWall::number_Hitboxes() const
 
 
 double
-EditorWall::scroll_DeltaToEye(size_t line_id, double eye_y) const
+Editor::scroll_DeltaToEye(size_t line_id, double eye_y) const
 {
     if (line_id >= _lines.size()) return 0.0;
     return eye_y - _lines[line_id].y;
@@ -502,7 +505,7 @@ EditorWall::scroll_DeltaToEye(size_t line_id, double eye_y) const
 
 
 void
-EditorWall::bounce(size_t line_id)
+Editor::bounce(size_t line_id)
 {
     if (line_id < _lines.size())
         _lines[line_id].bounce_vel += ConfigWall::bounce_impulse;
@@ -510,7 +513,7 @@ EditorWall::bounce(size_t line_id)
 
 
 void
-EditorWall::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
+Editor::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
 {
     if (_lines.empty()) return;
 
@@ -588,7 +591,7 @@ EditorWall::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
 
 
 double
-EditorWall::get_GridOrigin() const
+Editor::get_GridOrigin() const
 {
     double origin = 0.0;
     bool   found  = false;
@@ -600,7 +603,7 @@ EditorWall::get_GridOrigin() const
 }
 
 double
-EditorWall::snap_RowY(double y) const
+Editor::snap_RowY(double y) const
 {
     const double LH     = ConfigWall::line_height;
     const double origin = get_GridOrigin();
@@ -609,7 +612,7 @@ EditorWall::snap_RowY(double y) const
 }
 
 bool
-EditorWall::row_IsEmpty(double y) const
+Editor::row_IsEmpty(double y) const
 {
     const double LH     = ConfigWall::line_height;
     const double slot_y = snap_RowY(y);
@@ -619,3 +622,5 @@ EditorWall::row_IsEmpty(double y) const
     }
     return true;
 }
+
+} // namepsace Wall
diff --git a/src/wall/editor_wall.hpp b/src/wall/editor.hpp
similarity index 90%
rename from src/wall/editor_wall.hpp
rename to src/wall/editor.hpp
index feb666c..c1cde5f 100644
--- a/src/wall/editor_wall.hpp
+++ b/src/wall/editor.hpp
@@ -3,16 +3,17 @@
 #include "text_3d/text_3d.hpp"
 #include "utils/globals.hpp"
 #include "utils/light.hpp"
-#include "utils/math.hpp"
 #include "wall.hpp"
 
 class Camera;
 class GlRenderer;
 
+namespace Wall {
 
-class EditorWall
+class Editor
 {
-    struct Line {
+    struct Line
+    {
         int    shown_number {-1};
         double y            {0.0};
         double bounce_off   {0.0};
@@ -21,15 +22,17 @@ class EditorWall
         Text3dPtr num_left;
         Text3dPtr num_right;
 
-        DynArray<Text3d*>   words; // left-to-right
+        DynArray<Text3d*>   words;
     };
 
-    struct Placement {
+    struct Placement
+    {
         size_t insert_index;
         double z;
     };
 
-    struct Target {
+    struct Target
+    {
         enum Kind { Merge, Insert } kind;
         size_t   line_index;
         double   new_y;
@@ -52,8 +55,8 @@ public:
 
     struct NumberHit {
         size_t index;
-        Vec3   aabb_min;
-        Vec3   aabb_max;
+        Vec3   aabb_Min;
+        Vec3   aabb_Max;
     };
 
     void clear  ();
@@ -77,3 +80,5 @@ public:
     DynArray<NumberHit>
            number_Hitboxes() const;
 };
+
+} // namespace Wall
diff --git a/src/wall/wall_label.cpp b/src/wall/label.cpp
similarity index 87%
rename from src/wall/wall_label.cpp
rename to src/wall/label.cpp
index fb7ecbc..dde80d5 100644
--- a/src/wall/wall_label.cpp
+++ b/src/wall/label.cpp
@@ -1,5 +1,3 @@
-#include "wall_label.hpp"
-
 #include "entities/camera.hpp"
 #include "rendering/gl_renderer.hpp"
 #include "utils/config.hpp"
@@ -37,10 +35,10 @@ static SDL_FColor label_Color(Wall::Role r)
 
 // ── generate_All ─────────────────────────────────────────────────────────────
 
-DynArray<WallLabel>
-WallLabel::generate_All(float world_scale)
+DynArray<Wall::Label>
+Wall::Label::generate_All(float world_scale)
 {
-    DynArray<WallLabel> labels;
+    DynArray<Wall::Label> labels;
     labels.reserve(4);
 
     const float label_y = -world_scale * 0.48f;
@@ -55,7 +53,7 @@ WallLabel::generate_All(float world_scale)
 
     for (uint8_t ri = 0; ri < 4; ++ri) {
         Wall::Role      role = static_cast<Wall::Role> (ri);
-        Wall::Position  pos  = Wall::position_of       (role);
+        Wall::Position  pos  = Wall::position_Of       (role);
         Wall::Transform tf   = Wall::get_Transform     (role, world_scale);
 
         Vec3 anch = tf.position;
@@ -68,7 +66,7 @@ WallLabel::generate_All(float world_scale)
             case Wall::Position::NegZ: anch.z += extra_offset; break;
         }
 
-        WallLabel wl;
+        Wall::Label wl;
         wl.role     = role;
         wl.anchor   = anch;
         wl.face_yaw = tf.yaw;
@@ -90,9 +88,9 @@ WallLabel::generate_All(float world_scale)
 // ── on_Hit ───────────────────────────────────────────────────────────────────
 
 void
-WallLabel::on_Hit(size_t word_index, const Vec3& projectile_vel)
+Wall::Label::on_Hit(size_t word_index, const Vec3& projectile_vel)
 {
-    const Vec3 normal = wall_InwardNormal(Wall::position_of(role));
+    const Vec3 normal = Wall::inward_Normal(Wall::position_Of(role));
     label.kick(word_index, projectile_vel, normal);
 }
 
@@ -100,7 +98,7 @@ WallLabel::on_Hit(size_t word_index, const Vec3& projectile_vel)
 // ── update ───────────────────────────────────────────────────────────────────
 
 void
-WallLabel::update(double dt, const Camera& camera)
+Wall::Label::update(double dt, const Camera& camera)
 {
     // Positions + jiggle spring first. In non-billboard mode TextLabel::update
     // forces every word's pitch to 0, so we must apply our eye-tilt AFTER it,
@@ -111,8 +109,8 @@ WallLabel::update(double dt, const Camera& camera)
     // Tilt up/down toward the player's eye, clamped — identical to the
     // editor wall text tilt in wall.hpp::tilt_TowardEye. Shared anchor pitch
     // keeps the whole word reading as one rigid plane.
-    const float pitch = Wall::tilt_TowardEye(anchor, camera.pos);
-    for (const Text3dPtr& w : label.words())
+    const float pitch = Wall::Text::tilt_TowardEye(anchor, camera.pos);
+    for (const Text3dPtr& w : label.get_Words())
         if (w) w->pitch = pitch;
 }
 
@@ -120,7 +118,7 @@ WallLabel::update(double dt, const Camera& camera)
 // ── draw ─────────────────────────────────────────────────────────────────────
 
 void
-WallLabel::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
+Wall::Label::draw(GlRenderer& gl, const Camera& camera, const Light& light) const
 {
     label.draw(gl, camera, light);
 }
diff --git a/src/wall/wall_surfaces.cpp b/src/wall/surfaces.cpp
similarity index 73%
rename from src/wall/wall_surfaces.cpp
rename to src/wall/surfaces.cpp
index 20c705d..6d2fa57 100644
--- a/src/wall/wall_surfaces.cpp
+++ b/src/wall/surfaces.cpp
@@ -1,8 +1,13 @@
-#include "wall_surfaces.hpp"
-
 #include <SDL3/SDL.h>
 
 #include "entities/camera.hpp"
+#include "wall.hpp"
+
+#include "rendering/gl_renderer.hpp"
+#include "utils/globals.hpp"
+#include "utils/light.hpp"
+#include "utils/math.hpp"
+
 
 
 namespace {
@@ -12,7 +17,7 @@ namespace {
 //
 // Vertices wound CCW when viewed from inside the room.
 static void
-build_Wall(WallSurfaces::WallQuad& out,
+build_Wall(Wall::Surfaces::Quad& out,
            Wall::Position          pos,
            float                   world_scale,
            SDL_FColor              col)
@@ -97,23 +102,27 @@ build_Wall(WallSurfaces::WallQuad& out,
 } // namespace
 
 
+
+namespace Wall
+{
+
 void
-WallSurfaces::generate(float world_scale)
+Surfaces::generate(float world_scale)
 {
     _walls.clear();
     _walls.resize(4);
 
     struct Spec {
-        Wall::Role     role;
-        Wall::Position pos;
+        Role     role;
+        Position pos;
         SDL_FColor     color;
         bool           is_editor;
     };
     const Spec specs[4] = {
-        { Wall::Role::Editor,   Wall::Position::NegX, ConfigColor::editor,   false },
-        { Wall::Role::Program,  Wall::Position::PosX, ConfigColor::program,  false },
-        { Wall::Role::Info,     Wall::Position::PosZ, ConfigColor::info,     false },
-        { Wall::Role::Compiler, Wall::Position::NegZ, ConfigColor::compiler, false },
+        { Role::Editor,   Position::NegX, ConfigColor::editor,   false },
+        { Role::Program,  Position::PosX, ConfigColor::program,  false },
+        { Role::Info,     Position::PosZ, ConfigColor::info,     false },
+        { Role::Compiler, Position::NegZ, ConfigColor::compiler, false },
     };
 
     for (size_t i = 0; i < 4; ++i) {
@@ -125,29 +134,32 @@ WallSurfaces::generate(float world_scale)
 
 
 void
-WallSurfaces::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
+Surfaces::draw(GlRenderer& gl, const Camera& cam, const Light& light) const
 {
     if (_walls.empty()) return;
 
-    Mat4 view  = buildViewMat4(cam);
-    Mat4 proj  = gl.projection();
-    Mat4 model = Mat4::identity();
-    Mat4 mvp   = Mat4::mul(proj, Mat4::mul(view, model));
+    Mat4 view  = buildViewMat4    (cam);
+    Mat4 proj  = gl.get_Projection();
+    Mat4 model = Mat4::identity   ();
+    Mat4 mvp   = Mat4::mul        (proj, Mat4::mul(view, model));
 
-    gl.set_Wireframe(false);
-    gl.set_MVP(model, mvp);
-    gl.set_NormalMat(model);
-    gl.set_Light(light);
+    gl.set_Wireframe      (false);
+    gl.set_MVP            (model, mvp);
+    gl.set_NormalMat      (model);
+    gl.set_Light          (light);
     gl.set_TextLineSpacing(ConfigWall::text_line_spacing);
 
-    for (const WallQuad& w : _walls) {
-        gl.set_Color(w.color.r, w.color.g, w.color.b);
+    for (const Quad& w : _walls) {
+        gl.set_Color           (w.color.r, w.color.g, w.color.b);
         gl.enable_WallPaperMode(w.is_editor);
-        gl.set_ColorUseVertex(false);
-        gl.draw_MeshColored(w.verts.data(),
-                           static_cast<int>(w.verts.size() / 9),
-                           w.indices.data(),
-                           static_cast<int>(w.indices.size()));
+        gl.set_ColorUseVertex  (false);
+        gl.draw_MeshColored    (w.verts.data(),
+                                static_cast<int>(w.verts.size() / 9),
+                                w.indices.data(),
+                                static_cast<int>(w.indices.size()));
     }
     gl.enable_WallPaperMode(false);
 }
+
+
+} // Wall
diff --git a/src/wall/text_wall.cpp b/src/wall/text.cpp
similarity index 55%
rename from src/wall/text_wall.cpp
rename to src/wall/text.cpp
index 7abb641..676edcd 100644
--- a/src/wall/text_wall.cpp
+++ b/src/wall/text.cpp
@@ -1,11 +1,13 @@
 #include "entities/world.hpp"
 #include "systems/cpp_highlight_system.hpp"
-#include "text_wall.hpp"
 #include "utils/config.hpp"
+#include "wall/wall.hpp"
 
 
-TextWallPtr
-TextWall::from_Drop(Text3dPtr src)
+namespace Wall {
+
+Ptr
+Text::from_Drop(Text3dPtr src)
 {
     double ws   = World::get_BoxScale<double>();
     double x = src->pos.x;
@@ -36,9 +38,9 @@ TextWall::from_Drop(Text3dPtr src)
 
     src->yaw = yaw;
 
-    Wall::Role role = Wall::role_of(wall_pos);
+    Wall::Role role = Wall::role_Of(wall_pos);
 
-    return cpputils::make_unique<TextWall>(TextWall{
+    return cpputils::make_unique<Wall::Text>(Wall::Text{
         wall_pos,
         role,
         std::move(src)
@@ -47,12 +49,12 @@ TextWall::from_Drop(Text3dPtr src)
 
 
 std::string
-TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_threshold)
+Text::extract_Text(const PtrList& texts, Wall::Role role, double line_threshold)
 {
-    DynArray<TextWall*> items;
+    DynArray<Wall::Text*> items;
     items.reserve(texts.size());
 
-    for (const TextWallPtr& wt : texts) {
+    for (const Ptr& wt : texts) {
         if (wt->role == role)
             items.push_back(wt.get());
     }
@@ -60,29 +62,29 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
     if (items.empty())
         return "";
 
-    const Wall::Position wall_pos = Wall::position_of(role);
+    const Wall::Position wall_pos = Wall::position_Of(role);
 
     std::sort(items.begin(), items.end(),
-        [](const TextWall* a, const TextWall* b) {
+        [](const Wall::Text* a, const Wall::Text* b) {
             return a->text3d->pos.y > b->text3d->pos.y;
         });
 
     struct Line {
-        DynArray<TextWall*> items;
+        DynArray<Wall::Text*> items;
         double sum_y = 0.0;
     };
 
     DynArray<Line> lines;
     lines.reserve(items.size());
 
-    for (TextWall* wt : items) {
+    for (Wall::Text* wt : items) {
         const double y = wt->text3d->pos.y;
 
         if (!lines.empty()) {
             Line& line = lines.back();
             const double avg_y = line.sum_y / static_cast<double>(line.items.size());
 
-            if (std::abs(y - avg_y) < line_threshold) {
+            if (SDL_fabs(y - avg_y) < line_threshold) {
                 line.items.push_back(wt);
                 line.sum_y += y;
                 continue;
@@ -94,7 +96,7 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
 
     for (Line& line : lines) {
         std::sort(line.items.begin(), line.items.end(),
-            [&](const TextWall* a, const TextWall* b) {
+            [&](const Wall::Text* a, const Wall::Text* b) {
                 if (wall_pos == Wall::Position::PosX ||
                     wall_pos == Wall::Position::NegX)
                     return a->text3d->pos.z > b->text3d->pos.z;
@@ -108,7 +110,7 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
         for (size_t i = 0; i < line.items.size(); ++i) {
             if (i) result += ' ';
 
-            const TextWall* wt = line.items[i];
+            const Wall::Text* wt = line.items[i];
             if (wt->text3d->type == ObjectType::Text)
                 result += wt->text3d->text;
         }
@@ -120,28 +122,26 @@ TextWall::extract_Text(const TextWallList& texts, Wall::Role role, double line_t
 
 
 void
-TextWall::draw(GlRenderer& g, const Camera& c, const Light& l) const
+Text::draw(GlRenderer& g, const Camera& c, const Light& l) const
 {
     text3d->draw(g, c, l);
 }
 
 
-
-
 void
-TextWall::show_TokenInfo(TextWallList& texts, const std::string& token_text)
+Text::show_TokenInfo(PtrList& texts, const std::string& token_text)
 {
     texts.erase(
         std::remove_if(texts.begin(), texts.end(),
-            [](const TextWallPtr& wt){ return wt->role == Wall::Role::Info; }),
+            [](const Ptr& wt){ return wt->role == Wall::Role::Info; }),
         texts.end());
 
     Wall::Transform tf = Wall::get_Transform(Wall::Role::Info, World::get_BoxScale());
 
     TokenType        tt = CppHighlight::classify_Word(token_text);
-    TokenDB::Desc    d  = TokenDB::describe(token_text, tt);
+    TokenDB::Desc    d  = TokenDB::get_Description(token_text, tt);
 
-    std::string line1 = token_text + "  [" + TokenDB::type_Name(tt) + "]";
+    std::string line1 = token_text + "  [" + TokenDB::get_TypeName(tt) + "]";
     std::string line2 = d.short_desc;
     std::string line3 = d.long_desc;
 
@@ -151,8 +151,78 @@ TextWall::show_TokenInfo(TextWallList& texts, const std::string& token_text)
         Vec3 pos = tf.position; pos.y = y;
         Text3dPtr t = make_Text3d(line, Text3d::depth_wall, 0.003f, pos, ConfigColor::white);
         t->yaw = tf.yaw;
-        texts.push_back(cpputils::make_unique<TextWall>(TextWall{
+        texts.push_back(cpputils::make_unique<Wall::Text>(Wall::Text{
             tf.wall_position, Wall::Role::Info, std::move(t) }));
         y -= ConfigWall::text_line_spacing;
     }
 }
+
+
+float
+Text::tilt_TowardEye(const Vec3& text_pos, const Vec3& eye_pos)
+{
+    double dx = eye_pos.x - text_pos.x;
+    double dy = eye_pos.y - text_pos.y;
+    double dz = eye_pos.z - text_pos.z;
+
+    double horiz = SDL_sqrt(dx*dx + dz*dz);
+    if (horiz < 0.01) return 0.0f;          // player directly above/below — no tilt
+
+    // Sign flipped: we want positive pitch when player is BELOW the text.
+    double pitch = -SDL_atan2(dy, horiz);
+
+    if (pitch >  static_cast<double>(ConfigWall::max_tilt)) pitch =  ConfigWall::max_tilt;
+    if (pitch < -static_cast<double>(ConfigWall::max_tilt)) pitch = -ConfigWall::max_tilt;
+    return static_cast<float>(pitch);
+}
+
+
+void
+Text::clear_ToFloor(Wall::PtrList& texts,
+               DynArray<Text3dPtr>& words,
+               Wall::Role role)
+{
+    for (Wall::Ptr& wt : texts) {
+        if (wt->role != role || !wt->text3d) continue;
+
+        Text3dPtr word  = std::move(wt->text3d);
+        word->body.mode = PhysicsMode::Dynamic;
+        word->body.vel  = { 0.0, 1.5, 0.0 };
+        word->body.hover_height = World::get_FloorY<double>() + 1.5;
+
+        word->set_Look(ConfigColor::floor, Text3d::depth_floor);
+
+        words.push_back(std::move(word));
+    }
+
+    texts.erase(
+        std::remove_if(texts.begin(), texts.end(),
+            [role](const Wall::Ptr& wt){
+                return wt->role == role && !wt->text3d;
+            }),
+        texts.end());
+}
+
+
+void
+Text::scroll(Wall::PtrList& texts, Wall::Role role, float delta)
+{
+    for (Wall::Ptr& wt : texts) {
+        if (wt->role == role && wt->text3d) {
+            wt->text3d->pos.y += static_cast<double>(delta);
+        }
+    }
+}
+
+
+void
+Text::scroll_Up  (Wall::PtrList& texts, Wall::Role role)
+{ scroll(texts, role,  ConfigWall::scroll_step); }
+
+
+void
+Text::scroll_Down(Wall::PtrList& texts, Wall::Role role)
+{ scroll(texts, role, -ConfigWall::scroll_step); }
+
+
+} // namespace Wall
diff --git a/src/wall/text_wall.hpp b/src/wall/text_wall.hpp
deleted file mode 100644
index 636c425..0000000
--- a/src/wall/text_wall.hpp
+++ /dev/null
@@ -1,23 +0,0 @@
-#pragma once
-
-#include "wall/wall.hpp"
-#include "text_3d/text_3d.hpp"
-#include "utils/globals.hpp"
-#include "cpp_token/token_db.hpp"
-
-class GlRenderer;
-
-struct TextWall
-{
-    Wall::Position wall_position;
-    Wall::Role     role;
-    Text3dPtr      text3d;
-
-    void draw         (GlRenderer& gl, const Camera& camera, const Light& light) const;
-    static TextWallPtr
-         from_Drop    (Text3dPtr src);
-    static std::string
-         extract_Text (const TextWallList&, Wall::Role, double line_threshold = 0.3);
-    static void
-         show_TokenInfo(TextWallList& texts, const std::string& token_text);
-};
diff --git a/src/wall/text_wall_scroll.hpp b/src/wall/text_wall_scroll.hpp
deleted file mode 100644
index 5fa89c9..0000000
--- a/src/wall/text_wall_scroll.hpp
+++ /dev/null
@@ -1,52 +0,0 @@
-#pragma once
-
-#include "entities/world.hpp"
-#include "text_wall.hpp"
-#include "utils/config.hpp"
-#include "wall/wall.hpp"
-
-namespace TextWallScroll
-{
-    inline void
-    scroll(TextWallList& texts, Wall::Role role, float delta)
-    {
-        for (TextWallPtr& wt : texts) {
-            if (wt->role == role && wt->text3d) {
-                wt->text3d->pos.y += static_cast<double>(delta);
-            }
-        }
-    }
-
-    inline void
-    scroll_Up  (TextWallList& texts, Wall::Role role)
-    { scroll(texts, role,  ConfigWall::scroll_step); }
-
-    inline void
-    scroll_Down(TextWallList& texts, Wall::Role role)
-    { scroll(texts, role, -ConfigWall::scroll_step); }
-
-    inline void
-    clear_ToFloor(TextWallList& texts,
-                   DynArray<Text3dPtr>& words,
-                   Wall::Role role)
-    {
-        for (TextWallPtr& wt : texts) {
-            if (wt->role != role || !wt->text3d) continue;
-
-            Text3dPtr word = std::move(wt->text3d);
-            word->body.mode    = PhysicsMode::Dynamic;
-            word->body.vel     = { 0.0, 1.5, 0.0 };
-            word->body.hover_height = World::get_FloorY<double>() + 1.5;
-            word->set_Look(ConfigColor::floor, Text3d::depth_floor);
-
-            words.push_back(std::move(word));
-        }
-
-        texts.erase(
-            std::remove_if(texts.begin(), texts.end(),
-                [role](const TextWallPtr& wt){
-                    return wt->role == role && !wt->text3d;
-                }),
-            texts.end());
-    }
-}
diff --git a/src/wall/wall.cpp b/src/wall/wall.cpp
new file mode 100644
index 0000000..2e645f5
--- /dev/null
+++ b/src/wall/wall.cpp
@@ -0,0 +1,77 @@
+#include "entities/world.hpp"
+#include "wall.hpp"
+
+namespace Wall
+{
+
+    Role
+    role_Of(Position p)
+    {
+        switch (p) {
+            case Position::PosX: return Role::Program;
+            case Position::NegX: return Role::Editor;
+            case Position::PosZ: return Role::Info;
+            case Position::NegZ: return Role::Compiler;
+        }
+        return Role::Program;
+    }
+
+    Position
+    position_Of(Role r)
+    {
+        switch (r) {
+            case Role::Program:  return Position::PosX;
+            case Role::Editor:   return Position::NegX;
+            case Role::Info:     return Position::PosZ;
+            case Role::Compiler: return Position::NegZ;
+        }
+        return Position::PosX;
+    }
+
+    static_assert(static_cast<uint8_t>(Position::PosX) == static_cast<uint8_t>(Role::Program), "");
+    static_assert(static_cast<uint8_t>(Position::NegX) == static_cast<uint8_t>(Role::Editor),  "");
+    static_assert(static_cast<uint8_t>(Position::PosZ) == static_cast<uint8_t>(Role::Info),    "");
+    static_assert(static_cast<uint8_t>(Position::NegZ) == static_cast<uint8_t>(Role::Compiler),"");
+
+    Vec3 inward_Normal(Wall::Position pos)
+    {
+        switch (pos) {
+            case Wall::Position::PosX: return { -1.0, 0.0,  0.0 };
+            case Wall::Position::NegX: return {  1.0, 0.0,  0.0 };
+            case Wall::Position::PosZ: return {  0.0, 0.0, -1.0 };
+            case Wall::Position::NegZ: return {  0.0, 0.0,  1.0 };
+        }
+        return { 0.0, 0.0, 1.0 };
+    }
+
+    Transform
+    get_Transform(Role role, float world_scale)
+    {
+
+        switch (position_Of(role)) {
+            case Position::PosX:
+                return { Position::PosX,
+                         { world_scale - ConfigWall::text_offset, 0.0, 0.0 },
+                         -SDL_PI_F * 0.5f };
+            case Position::NegX:
+                return { Position::NegX,
+                         { -world_scale + ConfigWall::text_offset, 0.0, 0.0 },
+                         SDL_PI_F * 0.5f };
+            case Position::PosZ:
+                return { Position::PosZ,
+                         { 0.0, 0.0, world_scale - ConfigWall::text_offset },
+                         SDL_PI_F };
+            case Position::NegZ:
+            default:
+                return { Position::NegZ,
+                         { 0.0, 0.0, -world_scale + ConfigWall::text_offset },
+                         0.0f };
+        }
+    }
+
+    Vec3
+    get_Position(Role role, float world_scale)
+    {
+        return get_Transform(role, world_scale).position;
+    }
+} // namespace Wall
diff --git a/src/wall/wall.hpp b/src/wall/wall.hpp
index ff7b6bc..08c349a 100644
--- a/src/wall/wall.hpp
+++ b/src/wall/wall.hpp
@@ -1,97 +1,87 @@
 #pragma once
 
-#include "utils/globals.hpp"
+#include "text_3d/text_3d.hpp"
+#include "text_3d/text_label.hpp"
 #include "utils/config.hpp"
+#include "utils/globals.hpp"
+
 
-namespace Wall {
+namespace Wall
+{
+    struct Text;
+    using Ptr     = cpputils::unique_ptr<Text>;
+    using PtrList = DynArray<Ptr>;
 
     enum class Position : uint8_t { PosX,    NegX,   PosZ,    NegZ     };
     enum class Role     : uint8_t { Program, Editor, Info,    Compiler };
 
-    constexpr Role
-    role_of(Position p)
-    {
-        switch (p) {
-            case Position::PosX: return Role::Program;
-            case Position::NegX: return Role::Editor;
-            case Position::PosZ: return Role::Info;
-            case Position::NegZ: return Role::Compiler;
-        }
-        return Role::Program;
-    }
-
-    constexpr Position
-    position_of(Role r)
-    {
-        switch (r) {
-            case Role::Program:  return Position::PosX;
-            case Role::Editor:   return Position::NegX;
-            case Role::Info:     return Position::PosZ;
-            case Role::Compiler: return Position::NegZ;
-        }
-        return Position::PosX;
-    }
-
-    static_assert(static_cast<uint8_t>(Position::PosX) == static_cast<uint8_t>(Role::Program), "");
-    static_assert(static_cast<uint8_t>(Position::NegX) == static_cast<uint8_t>(Role::Editor),  "");
-    static_assert(static_cast<uint8_t>(Position::PosZ) == static_cast<uint8_t>(Role::Info),    "");
-    static_assert(static_cast<uint8_t>(Position::NegZ) == static_cast<uint8_t>(Role::Compiler),"");
-
-    struct
-    Transform
+    Role     role_Of      (Position p);
+    Position position_Of  (Role r);
+    Vec3     inward_Normal(Wall::Position pos);
+
+    struct Transform
     {
         Position wall_position;
-        Vec3 position;
-        float yaw;
+        Vec3     position;
+        float    yaw;
     };
 
-    static inline Transform
-    get_Transform(Role role, float world_scale)
-    {
+    Transform get_Transform (Role role, float world_scale);
+    Vec3      get_Position  (Role role, float world_scale);
 
-        switch (position_of(role)) {
-            case Position::PosX:
-                return { Position::PosX,
-                         { world_scale - ConfigWall::text_offset, 0.0, 0.0 },
-                         -SDL_PI_F * 0.5f };
-            case Position::NegX:
-                return { Position::NegX,
-                         { -world_scale + ConfigWall::text_offset, 0.0, 0.0 },
-                         SDL_PI_F * 0.5f };
-            case Position::PosZ:
-                return { Position::PosZ,
-                         { 0.0, 0.0, world_scale - ConfigWall::text_offset },
-                         SDL_PI_F };
-            case Position::NegZ:
-            default:
-                return { Position::NegZ,
-                         { 0.0, 0.0, -world_scale + ConfigWall::text_offset },
-                         0.0f };
-        }
-    }
-
-    static inline Vec3
-    get_Position(Role role, float world_scale)
+
+    class Surfaces
     {
-        return get_Transform(role, world_scale).position;
-    }
+    public:
+        struct Quad {
+            bool       is_editor;
+            Wall::Role role;
+            SDL_FColor color;
 
+            DynArray<float> verts;
+            DynArray<int>   indices;
+        };
 
-    static inline float
-    tilt_TowardEye(const Vec3& text_pos, const Vec3& eye_pos)
+        void generate(float world_scale);
+        void draw(GlRenderer& gl, const Camera& cam, const Light& light) const;
+    private:
+        DynArray<Quad> _walls;
+    };
+
+    struct Text
     {
-        double dx = eye_pos.x - text_pos.x;
-        double dy = eye_pos.y - text_pos.y;
-        double dz = eye_pos.z - text_pos.z;
+        Wall::Position wall_position;
+        Wall::Role     role;
+        Text3dPtr      text3d;
+
+        void draw (GlRenderer& gl, const Camera& camera, const Light& light) const;
+
+        static void        show_TokenInfo(PtrList& texts, const std::string& token_text);
+        static Ptr         from_Drop     (Text3dPtr src);
+        static std::string extract_Text  (const PtrList&, Wall::Role, double line_threshold = 0.3);
+        static float       tilt_TowardEye(const Vec3& text_pos, const Vec3& eye_pos);
+        static void        clear_ToFloor (Wall::PtrList& texts,
+                                          DynArray<Text3dPtr>& words,
+                                          Wall::Role role);
+        static void        scroll        (Wall::PtrList& texts, Wall::Role role, float delta);
+        static void        scroll_Up     (Wall::PtrList& texts, Wall::Role role);
+        static void        scroll_Down   (Wall::PtrList& texts, Wall::Role role);
+    };
 
-        double horiz = SDL_sqrt(dx*dx + dz*dz);
-        if (horiz < 0.01) return 0.0f;          // player directly above/below — no tilt
 
-        // Sign flipped: we want positive pitch when player is BELOW the text.
-        double pitch = -SDL_atan2(dy, horiz);
 
-        if (pitch >  static_cast<double>(ConfigWall::max_tilt)) pitch =  ConfigWall::max_tilt;
-        if (pitch < -static_cast<double>(ConfigWall::max_tilt)) pitch = -ConfigWall::max_tilt;
-        return static_cast<float>(pitch);
-    }
+    struct Label
+    {
+        Wall::Role role;
+        float      face_yaw;
+        Vec3       anchor;
+        TextLabel  label;
+
+        static DynArray<Label>
+            generate_All(float world_scale);
+
+        void on_Hit (size_t word_index, const Vec3& projectile_vel);
+        void update (double dt, const Camera& camera);
+        void draw   (GlRenderer& gl, const Camera& camera, const Light& light) const;
+    };
 }
diff --git a/src/wall/wall_label.hpp b/src/wall/wall_label.hpp
deleted file mode 100644
index 96af1bc..0000000
--- a/src/wall/wall_label.hpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#pragma once
-
-#include "text_3d/text_label.hpp"
-#include "utils/globals.hpp"
-#include "utils/light.hpp"
-#include "wall/wall.hpp"
-
-class GlRenderer;
-class Camera;
-
-struct WallLabel
-{
-    Wall::Role role;
-    float      face_yaw;
-    Vec3       anchor;
-    TextLabel  label;
-
-    static DynArray<WallLabel>
-    generate_All(float world_scale);
-
-    void on_Hit (size_t word_index, const Vec3& projectile_vel);
-    void update (double dt, const Camera& camera);
-    void draw   (GlRenderer& gl, const Camera& camera, const Light& light) const;
-};
-
-
-inline Vec3 wall_InwardNormal(Wall::Position pos)
-{
-    switch (pos) {
-        case Wall::Position::PosX: return { -1.0, 0.0,  0.0 };
-        case Wall::Position::NegX: return {  1.0, 0.0,  0.0 };
-        case Wall::Position::PosZ: return {  0.0, 0.0, -1.0 };
-        case Wall::Position::NegZ: return {  0.0, 0.0,  1.0 };
-    }
-    return { 0.0, 0.0, 1.0 };
-}
diff --git a/src/wall/wall_surfaces.hpp b/src/wall/wall_surfaces.hpp
deleted file mode 100644
index 100a25d..0000000
--- a/src/wall/wall_surfaces.hpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-
-#include <SDL3/SDL.h>
-
-#include "rendering/gl_renderer.hpp"
-#include "utils/globals.hpp"
-#include "utils/light.hpp"
-#include "utils/math.hpp"
-#include "wall/wall.hpp"
-
-class Camera;
-
-
-class WallSurfaces
-{
-public:
-    struct WallQuad {
-        bool       is_editor;
-        Wall::Role role;
-        SDL_FColor color;
-
-        DynArray<float> verts;
-        DynArray<int>   indices;
-    };
-
-    void generate(float world_scale);
-    void draw(GlRenderer& gl, const Camera& cam, const Light& light) const;
-private:
-    DynArray<WallQuad> _walls;
-};
-