diff --git a/doc/tutorial/07_input.cpp b/doc/tutorial/07_input.cpp
index 6d37bd7e..87a8c7e5 100644
--- a/doc/tutorial/07_input.cpp
+++ b/doc/tutorial/07_input.cpp
@@ -138,7 +138,7 @@ public:
                     m_yaw_angle += seconds * 0.2f;
             }
 
-            m_text->SetText(String::format(
+            m_text->SetText(lol::format(
                 "cursor: (%0.3f, %0.3f) - pixel (%d, %d)",
                 m_mouse->GetCursor(0).x, m_mouse->GetCursor(0).y,
                 m_mouse->GetCursorPixel(0).x, m_mouse->GetCursorPixel(0).y));
diff --git a/src/base/hash.cpp b/src/base/hash.cpp
index 122ab4af..17c7b4f9 100644
--- a/src/base/hash.cpp
+++ b/src/base/hash.cpp
@@ -163,6 +163,11 @@ uint32_t hash<char const *>::operator ()(char const *s) const
     return HashCharString(s);
 }
 
+uint32_t hash<std::string>::operator ()(std::string const &s) const
+{
+    return HashCharString(&s[0]);
+}
+
 uint32_t hash<char const *>::operator ()(String const &s) const
 {
     return HashCharString(&s[0]);
diff --git a/src/base/log.cpp b/src/base/log.cpp
index 7c47b5d9..62c3407b 100644
--- a/src/base/log.cpp
+++ b/src/base/log.cpp
@@ -94,7 +94,7 @@ void msg::helper(MessageType type, char const *fmt, va_list ap)
         ANDROID_LOG_ERROR
     };
 
-    String buf = String::vformat(fmt, ap);
+    std::string buf = vformat(fmt, ap);
     __android_log_print(prio[(int)type], "LOL", "[%d] %s", (int)gettid(), &buf[0]);
 
 #else
@@ -107,11 +107,11 @@ void msg::helper(MessageType type, char const *fmt, va_list ap)
     };
 
 #   if defined _WIN32
-    String buf = String(prefix[(int)type]) + ": " + String::vformat(fmt, ap);
+    std::string buf = std::string(prefix[(int)type]) + ": " + vformat(fmt, ap);
 
     array<WCHAR> widechar;
-    widechar.resize(buf.count() + 1);
-    MultiByteToWideChar(CP_UTF8, 0, buf.C(), buf.count() + 1, widechar.data(), widechar.count());
+    widechar.resize(buf.length() + 1);
+    MultiByteToWideChar(CP_UTF8, 0, buf.c_str(), buf.length() + 1, widechar.data(), widechar.count());
     OutputDebugStringW(widechar.data());
 #   else
     fprintf(stderr, "%s: ", prefix[(int)type]);
diff --git a/src/base/string.cpp b/src/base/string.cpp
index 29c5f7b7..8446737f 100644
--- a/src/base/string.cpp
+++ b/src/base/string.cpp
@@ -54,26 +54,17 @@ array<std::string> split(std::string const &s, std::string const &seps)
     return ret;
 }
 
-/*
- * XXX: deprecated
- */
-
-String String::format(char const *format, ...)
+std::string format(char const *format, ...)
 {
-    String ret;
-
     va_list ap;
     va_start(ap, format);
-    ret = String::vformat(format, ap);
+    std::string ret = vformat(format, ap);
     va_end(ap);
-
     return ret;
 }
 
-String String::vformat(char const *format, va_list ap)
+std::string vformat(char const *format, va_list ap)
 {
-    String ret;
-
     va_list ap2;
 #if defined va_copy || !defined _MSC_VER
     /* Visual Studio 2010 does not support va_copy. */
@@ -91,9 +82,8 @@ String String::vformat(char const *format, va_list ap)
     va_end(ap2);
 #endif
 
-    ((super &)ret).reserve(needed);
-    ret.m_count = needed;
-
+    std::string ret;
+    ret.resize(needed);
     vsnprintf(&ret[0], needed, format, ap);
 
     return ret;
diff --git a/src/image/color/color.cpp b/src/image/color/color.cpp
index d32ffd71..0c3f9e95 100644
--- a/src/image/color/color.cpp
+++ b/src/image/color/color.cpp
@@ -31,28 +31,28 @@ vec4 const Color::light_gray = vec4(.75f, .75f, .75f, 1);
 /*
  * Conversion from colours to hexadecimal
  */
-String Color::HexString4Bpp(vec3 c)
+std::string Color::HexString4Bpp(vec3 c)
 {
     uvec3 c2 = (uvec3)(clamp(c, 0.f, 1.f) * 255.999f);
-    return String::format("%01x%01x%01x", c2.r, c2.g, c2.b);
+    return format("%01x%01x%01x", c2.r, c2.g, c2.b);
 }
 
-String Color::HexString4Bpp(vec4 c)
+std::string Color::HexString4Bpp(vec4 c)
 {
     uvec4 c2 = (uvec4)(clamp(c, 0.f, 1.f) * 15.999f);
-    return String::format("%01x%1x%01x%01x", c2.r, c2.g, c2.b, c2.a);
+    return format("%01x%1x%01x%01x", c2.r, c2.g, c2.b, c2.a);
 }
 
-String Color::HexString8Bpp(vec3 c)
+std::string Color::HexString8Bpp(vec3 c)
 {
     uvec3 c2 = (uvec3)(clamp(c, 0.f, 1.f) * 255.999f);
-    return String::format("%02x%02x%02x", c2.r, c2.g, c2.b);
+    return format("%02x%02x%02x", c2.r, c2.g, c2.b);
 }
 
-String Color::HexString8Bpp(vec4 c)
+std::string Color::HexString8Bpp(vec4 c)
 {
     uvec4 c2 = (uvec4)(clamp(c, 0.f, 1.f) * 15.999f);
-    return String::format("%02x%2x%02x%02x", c2.r, c2.g, c2.b, c2.a);
+    return format("%02x%2x%02x%02x", c2.r, c2.g, c2.b, c2.a);
 }
 
 /*
diff --git a/src/input/input.h b/src/input/input.h
index 7f5a82ab..658a279e 100644
--- a/src/input/input.h
+++ b/src/input/input.h
@@ -20,9 +20,9 @@ static String g_name_joystick()
 {
     return String("Joystick");
 }
-static String g_name_joystick(const uint64_t num)
+static std::string g_name_joystick(const uint64_t num)
 {
-    return String::format("Joystick%d", (int)num);
+    return format("Joystick%d", (int)num);
 }
 
 #   define _SC(id, str, name) const String g_name_key_##name(#name);
diff --git a/src/lol/base/hash.h b/src/lol/base/hash.h
index e24e2301..b3d0631b 100644
--- a/src/lol/base/hash.h
+++ b/src/lol/base/hash.h
@@ -41,6 +41,11 @@ template<> struct hash<char const *>
     uint32_t operator()(String const &s) const;
 };
 
+template<> struct hash<std::string>
+{
+    uint32_t operator()(std::string const &s) const;
+};
+
 template<> struct hash<String>
 {
     uint32_t operator()(String const &s) const;
diff --git a/src/lol/base/string.h b/src/lol/base/string.h
index 3f2afaf2..b1bb6d81 100644
--- a/src/lol/base/string.h
+++ b/src/lol/base/string.h
@@ -30,6 +30,9 @@ array<std::string> split(std::string const &s, char sep);
 /* Split a string along multiple separators */
 array<std::string> split(std::string const &s, std::string const &seps);
 
+std::string format(char const *format, ...) LOL_ATTR_FORMAT(1, 2);
+std::string vformat(char const *format, va_list ap);
+
 } /* namespace lol */
 
 //
@@ -80,6 +83,12 @@ public:
         ((super &)*this)[item_count] = '\0';
     }
 
+    /* Legacy constructor for std::string */
+    inline String(std::string const &s)
+      : String(s.c_str())
+    {
+    }
+
     inline String(String const &s)
       : super((super const &)s)
     {
@@ -354,9 +363,6 @@ public:
 
         return res < 0;
     }
-
-    static String format(char const *format, ...) LOL_ATTR_FORMAT(1, 2);
-    static String vformat(char const *format, va_list ap);
 };
 
 inline String operator +(char c, String const &s)
diff --git a/src/lol/image/color.h b/src/lol/image/color.h
index 40d7b7ff..d378267d 100644
--- a/src/lol/image/color.h
+++ b/src/lol/image/color.h
@@ -337,10 +337,10 @@ public:
     /*
     * Convert colors to hex strings.
     */
-    static String HexString4Bpp(vec3 c);
-    static String HexString4Bpp(vec4 c);
-    static String HexString8Bpp(vec3 c);
-    static String HexString8Bpp(vec4 c);
+    static std::string HexString4Bpp(vec3 c);
+    static std::string HexString4Bpp(vec4 c);
+    static std::string HexString8Bpp(vec3 c);
+    static std::string HexString8Bpp(vec4 c);
 
     /*
     * Convert hex strings to colors.
diff --git a/src/lol/math/matrix.h b/src/lol/math/matrix.h
index 30cd790f..5ff32afc 100644
--- a/src/lol/math/matrix.h
+++ b/src/lol/math/matrix.h
@@ -133,7 +133,7 @@ struct LOL_ATTR_NODISCARD mat_t<T, 2, 2>
     }
 
     void printf() const;
-    String tostring() const;
+    std::string tostring() const;
 
     static const mat_t<T,2,2> identity;
 
@@ -260,7 +260,7 @@ struct LOL_ATTR_NODISCARD mat_t<T, 3, 3>
     }
 
     void printf() const;
-    String tostring() const;
+    std::string tostring() const;
 
     static const mat_t<T,3,3> identity;
 
@@ -436,7 +436,7 @@ struct LOL_ATTR_NODISCARD mat_t<T, 4, 4>
     static mat_t<T,4,4> shifted_perspective(T fov_y, T screen_size, T screen_ratio_yx, T near, T far);
 
     void printf() const;
-    String tostring() const;
+    std::string tostring() const;
 
     static const mat_t<T,4,4> identity;
 
diff --git a/src/lol/math/vector.h b/src/lol/math/vector.h
index 82393766..2efa4f4e 100644
--- a/src/lol/math/vector.h
+++ b/src/lol/math/vector.h
@@ -214,7 +214,7 @@ private:
     } \
     \
     void printf() const; \
-    class String tostring() const;
+    std::string tostring() const;
 
 /*
  * 2-element vectors
diff --git a/src/math/vector.cpp b/src/math/vector.cpp
index 9bc06991..2761e8dd 100644
--- a/src/math/vector.cpp
+++ b/src/math/vector.cpp
@@ -19,7 +19,7 @@ namespace lol
 
 #define LOL_PRINTF_TOSTRING(type, ...) \
 template<> void type::printf() const        { msg::debug(__VA_ARGS__); } \
-template<> String type::tostring() const    { return String::format(__VA_ARGS__); }
+template<> std::string type::tostring() const    { return format(__VA_ARGS__); }
 
 LOL_PRINTF_TOSTRING(vec2,   "[ %6.6f %6.6f ]\n", x, y);
 LOL_PRINTF_TOSTRING(ivec2,  "[ %i %i ]\n", x, y);
@@ -38,12 +38,12 @@ template<> void mat2::printf() const
     msg::debug("  %6.6f %6.6f ]\n", p[0][1], p[1][1]);
 }
 
-template<> String mat2::tostring() const
+template<> std::string mat2::tostring() const
 {
     mat2 const &p = *this;
 
-    return String::format("[ %6.6f %6.6f\n", p[0][0], p[1][0]) +
-           String::format("  %6.6f %6.6f ]\n", p[0][1], p[1][1]);
+    return format("[ %6.6f %6.6f\n", p[0][0], p[1][0]) +
+           format("  %6.6f %6.6f ]\n", p[0][1], p[1][1]);
 }
 
 template<> void mat3::printf() const
@@ -55,13 +55,13 @@ template<> void mat3::printf() const
     msg::debug("  %6.6f %6.6f %6.6f ]\n", p[0][2], p[1][2], p[2][2]);
 }
 
-template<> String mat3::tostring() const
+template<> std::string mat3::tostring() const
 {
     mat3 const &p = *this;
 
-    return String::format("[ %6.6f %6.6f %6.6f\n", p[0][0], p[1][0], p[2][0]) +
-           String::format("  %6.6f %6.6f %6.6f\n", p[0][1], p[1][1], p[2][1]) +
-           String::format("  %6.6f %6.6f %6.6f ]\n", p[0][2], p[1][2], p[2][2]);
+    return format("[ %6.6f %6.6f %6.6f\n", p[0][0], p[1][0], p[2][0]) +
+           format("  %6.6f %6.6f %6.6f\n", p[0][1], p[1][1], p[2][1]) +
+           format("  %6.6f %6.6f %6.6f ]\n", p[0][2], p[1][2], p[2][2]);
 }
 
 template<> void mat4::printf() const
@@ -78,18 +78,18 @@ template<> void mat4::printf() const
                p[0][3], p[1][3], p[2][3], p[3][3]);
 }
 
-template<> String mat4::tostring() const
+template<> std::string mat4::tostring() const
 {
     mat4 const &p = *this;
 
-    return String::format("[ %6.6f %6.6f %6.6f %6.6f\n",
-                            p[0][0], p[1][0], p[2][0], p[3][0]) +
-           String::format("  %6.6f %6.6f %6.6f %6.6f\n",
-                            p[0][1], p[1][1], p[2][1], p[3][1]) +
-           String::format("  %6.6f %6.6f %6.6f %6.6f\n",
-                            p[0][2], p[1][2], p[2][2], p[3][2]) +
-           String::format("  %6.6f %6.6f %6.6f %6.6f ]\n",
-                            p[0][3], p[1][3], p[2][3], p[3][3]);
+    return format("[ %6.6f %6.6f %6.6f %6.6f\n",
+                  p[0][0], p[1][0], p[2][0], p[3][0]) +
+           format("  %6.6f %6.6f %6.6f %6.6f\n",
+                  p[0][1], p[1][1], p[2][1], p[3][1]) +
+           format("  %6.6f %6.6f %6.6f %6.6f\n",
+                  p[0][2], p[1][2], p[2][2], p[3][2]) +
+           format("  %6.6f %6.6f %6.6f %6.6f ]\n",
+                  p[0][3], p[1][3], p[2][3], p[3][3]);
 }
 
 } /* namespace lol */
diff --git a/src/platform/sdl/sdlinput.cpp b/src/platform/sdl/sdlinput.cpp
index 77d1b5f2..e8121848 100644
--- a/src/platform/sdl/sdlinput.cpp
+++ b/src/platform/sdl/sdlinput.cpp
@@ -193,12 +193,12 @@ SdlInput::SdlInput(int app_w, int app_h, int screen_w, int screen_h)
             continue;
         }
 
-        //String::format("Joystick%d", i + 1).C()
+        //format("Joystick%d", i + 1).c_str()
         InputDeviceInternal* stick = new InputDeviceInternal(g_name_joystick(i + 1));
         for (int j = 0; j < SDL_JoystickNumAxes(sdlstick); ++j)
-            stick->AddAxis(String::format("Axis%d", j + 1).C());
+            stick->AddAxis(format("Axis%d", j + 1).c_str());
         for (int j = 0; j < SDL_JoystickNumButtons(sdlstick); ++j)
-            stick->AddKey(String::format("Button%d", j + 1).C());
+            stick->AddKey(format("Button%d", j + 1).c_str());
 
         m_data->m_joysticks.push(sdlstick, stick);
     }
diff --git a/src/t/base/map.cpp b/src/t/base/map.cpp
index b6739cb9..917abce6 100644
--- a/src/t/base/map.cpp
+++ b/src/t/base/map.cpp
@@ -72,12 +72,12 @@ lolunit_declare_fixture(map_test)
 
     lolunit_declare_test(map_remove_string)
     {
-        map<String, uint64_t> m;
-        array<String> a;
+        map<std::string, uint64_t> m;
+        array<std::string> a;
 
         for (int i = 0; i < 20; i++)
         {
-            a << String::format("test_str_%i", i);
+            a << format("test_str_%i", i);
             m[a.last()] = -1;
         }
         for (int i = 0; i < a.count(); i++)
diff --git a/src/t/base/string.cpp b/src/t/base/string.cpp
index 51bd13d9..677f137f 100644
--- a/src/t/base/string.cpp
+++ b/src/t/base/string.cpp
@@ -144,15 +144,15 @@ lolunit_declare_fixture(string_test)
     }
 
 
-    lolunit_declare_test(string_printf)
+    lolunit_declare_test(string_format)
     {
-        String s1 = "3a";
-        String s2 = String::format("%d%x", 3, 10);
+        std::string s1 = "3a";
+        std::string s2 = format("%d%x", 3, 10);
 
         lolunit_assert(s1 == s2);
 
-        String s3 = "abc 3";
-        String s4 = String::format("abc %d", 3);
+        std::string s3 = "abc 3";
+        std::string s4 = format("abc %d", 3);
 
         lolunit_assert(s3 == s4);
     }
diff --git a/src/t/image/color.cpp b/src/t/image/color.cpp
index 01785f2c..508c0f67 100644
--- a/src/t/image/color.cpp
+++ b/src/t/image/color.cpp
@@ -93,7 +93,7 @@ lolunit_declare_fixture(color_test)
             vec3 v2 = Color::RGBToHSV(v1);
             vec3 v3 = Color::HSVToRGB(v2);
 
-            String rgb = String::format("[%f %f %f]", v1.r, v1.g, v1.b);
+            std::string rgb = format("[%f %f %f]", v1.r, v1.g, v1.b);
             lolunit_set_context(&rgb[0]);
 
             if (r != g || g != b)
@@ -115,7 +115,7 @@ lolunit_declare_fixture(color_test)
             vec3 v2 = Color::RGBToHSL(v1);
             vec3 v3 = Color::HSVToHSL(Color::RGBToHSV(v1));
 
-            String rgb = String::format("[%f %f %f]", v1.r, v1.g, v1.b);
+            std::string rgb = format("[%f %f %f]", v1.r, v1.g, v1.b);
             lolunit_set_context(&rgb[0]);
 
             /* Don’t check hue if saturation is zero. */
diff --git a/src/text.cpp b/src/text.cpp
index bc77234e..23375256 100644
--- a/src/text.cpp
+++ b/src/text.cpp
@@ -60,7 +60,7 @@ void Text::SetText(String const &text)
 
 void Text::SetInt(int val)
 {
-    data->m_text = String::format("%i", val);
+    data->m_text = format("%i", val);
 }
 
 void Text::SetPos(vec3 pos)