diff --git a/game/engines/default/engine/HotkeysIconsDisplay.lua b/game/engines/default/engine/HotkeysIconsDisplay.lua
index ea1387bebf2c0a4eafdc4daa99f1c2dfc21381b8..4c3943bd91fe492f3f6402c4a466d1e025cab729 100644
--- a/game/engines/default/engine/HotkeysIconsDisplay.lua
+++ b/game/engines/default/engine/HotkeysIconsDisplay.lua
@@ -18,6 +18,7 @@
 -- darkgod@te4.org
 
 require "engine.class"
+local Shader = require "engine.Shader"
 local Entity = require "engine.Entity"
 local Tiles = require "engine.Tiles"
 local UI = require "engine.ui.Base"
@@ -242,6 +243,7 @@ end
 
 function _M:toScreen()
 	self:display()
+	local shader = Shader.default.textoutline and Shader.default.textoutline.shad
 	if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end
 	for i = 1, #self.items do
 		local item = self.items[i]
@@ -260,14 +262,23 @@ function _M:toScreen()
 --		frame[1]:toScreenFull(self.display_x + item.x, self.display_y + item.y, self.frames.w, self.frames.h, frame[2] * self.frames.rw, frame[3] * self.frames.rh, pagesel, pagesel, pagesel, 255)
 		UI:drawFrame(self.frames.base, self.display_x + item.x, self.display_y + item.y, frame[1], frame[2], frame[3], 1)
 
+		if self.shadow then
+			if shader then
+				shader:paramNumber2("outlineSize", 0.7, 0.7)
+				shader:paramNumber2("textSize", key._tex_w, key._tex_h)
+				shader:use(true)
+			else
+				key._tex:toScreenFull(self.display_x + item.x + 1 + self.frames.fx + self.icon_w - key.w, self.display_y + item.y + 1 + self.icon_h - key.h, key.w, key.h, key._tex_w, key._tex_h, 0, 0, 0, self.shadow)
+				if gtxt then gtxt._tex:toScreenFull(self.display_x + item.x + self.frames.fy + 2 + (self.icon_w - gtxt.fw) / 2, self.display_y + item.y + self.frames.fy + 2 + (self.icon_h - gtxt.fh) / 2, gtxt.w, gtxt.h, gtxt._tex_w, gtxt._tex_h, 0, 0, 0, self.shadow) end
+			end
+		end
+
+		key._tex:toScreenFull(self.display_x + item.x + self.frames.fx + self.icon_w - key.w, self.display_y + item.y + self.icon_h - key.h, key.w, key.h, key._tex_w, key._tex_h)
 		if gtxt then
-			if self.shadow then gtxt._tex:toScreenFull(self.display_x + item.x + self.frames.fy + 2 + (self.icon_w - gtxt.fw) / 2, self.display_y + item.y + self.frames.fy + 2 + (self.icon_h - gtxt.fh) / 2, gtxt.w, gtxt.h, gtxt._tex_w, gtxt._tex_h, 0, 0, 0, self.shadow) end
 			gtxt._tex:toScreenFull(self.display_x + item.x + self.frames.fx + (self.icon_w - gtxt.fw) / 2, self.display_y + item.y + self.frames.fy + (self.icon_h - gtxt.fh) / 2, gtxt.w, gtxt.h, gtxt._tex_w, gtxt._tex_h)
 		end
 
---		core.display.drawQuad(self.display_x + item.x + 1 + self.frames.fx + self.icon_w - key.w, self.display_y + item.y + 1 + self.icon_h - key.h, key.w, key.h, 0, 128, 128, 200)
-		if self.shadow then key._tex:toScreenFull(self.display_x + item.x + 1 + self.frames.fx + self.icon_w - key.w, self.display_y + item.y + 1 + self.icon_h - key.h, key.w, key.h, key._tex_w, key._tex_h, 0, 0, 0, self.shadow) end
-		key._tex:toScreenFull(self.display_x + item.x + self.frames.fx + self.icon_w - key.w, self.display_y + item.y + self.icon_h - key.h, key.w, key.h, key._tex_w, key._tex_h)
+		if self.shadow and shader then shader:use(false) end
 	end
 end
 
diff --git a/game/engines/default/engine/LogDisplay.lua b/game/engines/default/engine/LogDisplay.lua
index 75fc2407fa3c7be5d6628b80bcff1a4cc016233b..4435e949f7b7dc64039e8030c591cec305e1aa3d 100644
--- a/game/engines/default/engine/LogDisplay.lua
+++ b/game/engines/default/engine/LogDisplay.lua
@@ -230,6 +230,7 @@ function _M:toScreen()
 	if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end
 
 	local now = core.game.getTime()
+	local shader = Shader.default.textoutline and Shader.default.textoutline.shad
 
 	local h = self.display_y + self.h -  self.fh
 	for i = 1, #self.dlist do
@@ -246,15 +247,16 @@ function _M:toScreen()
 
 		self.dlist[i].dh = h
 		if self.shadow then
-			if shader.shad then
-				shader.shad:paramNumber2("textSize", item._tex_w, item._tex_h)
-				shader.shad:use(true)
+			if shader then
+				shader:paramNumber2("outlineSize", 0.7, 0.7)
+				shader:paramNumber2("textSize", item._tex_w, item._tex_h)
+				shader:use(true)
 			else
 				item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade)
 			end
 		end
 		item._tex:toScreenFull(self.display_x, h, item.w, item.h, item._tex_w, item._tex_h, 1, 1, 1, fade)
-		if self.shadow and shader.shad then shader.shad:use(false) end
+		if self.shadow and shader then shader:use(false) end
 		for di = 1, #item._dduids do item._dduids[di].e:toScreen(nil, self.display_x + item._dduids[di].x, h, item._dduids[di].w, item._dduids[di].w, fade, false, false) end
 		h = h - self.fh
 	end
diff --git a/game/engines/default/engine/Shader.lua b/game/engines/default/engine/Shader.lua
index e8810576fe655aff7466e379bd9b44d2b29e5e0a..043cf74986ce781b1aa0472195e35dbc097b66bc 100644
--- a/game/engines/default/engine/Shader.lua
+++ b/game/engines/default/engine/Shader.lua
@@ -183,3 +183,12 @@ function _M:setUniform(k, v)
 		end
 	end
 end
+
+----------------------------------------------------------------------------
+-- Default shaders
+----------------------------------------------------------------------------
+default = {}
+
+function _M:setDefault(kind, name, args)
+	default[kind] = _M.new(name, args)
+end
diff --git a/game/engines/default/engine/UserChat.lua b/game/engines/default/engine/UserChat.lua
index 7f61e3c9bfecb1e5e78c82d0503421a2e56c170c..e15c92fead4dc8716af8a19a28f6dc44b80f9ad9 100644
--- a/game/engines/default/engine/UserChat.lua
+++ b/game/engines/default/engine/UserChat.lua
@@ -18,6 +18,7 @@
 -- darkgod@te4.org
 
 require "engine.class"
+local Shader = require "engine.Shader"
 local KeyBind = require "engine.KeyBind"
 local Mouse = require "engine.Mouse"
 local Dialog = require "engine.ui.Dialog"
@@ -655,6 +656,9 @@ end
 
 function _M:toScreen()
 	self:display()
+
+	local shader = Shader.default.textoutline and Shader.default.textoutline.shad
+
 	if self.bg_texture then self.bg_texture:toScreenFull(self.display_x, self.display_y, self.w, self.h, self.bg_texture_w, self.bg_texture_h) end
 	local h = self.display_y + self.h -  self.fh
 	local now = core.game.getTime()
@@ -671,8 +675,17 @@ function _M:toScreen()
 		end
 
 		self.dlist[i].dh = h
-		if self.shadow then item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade) end
+		if self.shadow then
+			if shader then
+				shader:paramNumber2("outlineSize", 0.7, 0.7)
+				shader:paramNumber2("textSize", item._tex_w, item._tex_h)
+				shader:use(true)
+			else
+				item._tex:toScreenFull(self.display_x+2, h+2, item.w, item.h, item._tex_w, item._tex_h, 0,0,0, self.shadow * fade)
+			end
+		end
 		item._tex:toScreenFull(self.display_x, h, item.w, item.h, item._tex_w, item._tex_h, 1, 1, 1, fade)
+		if self.shadow and shader then shader:use(false) end
 		h = h - self.fh
 	end
 
diff --git a/game/modules/tome/class/uiset/Minimalist.lua b/game/modules/tome/class/uiset/Minimalist.lua
index 6168fbc3b3acef8ed225f57e2026292d4840b49a..19d07da85952c99d375a5f319655190ebf28c3f9 100644
--- a/game/modules/tome/class/uiset/Minimalist.lua
+++ b/game/modules/tome/class/uiset/Minimalist.lua
@@ -328,6 +328,8 @@ function _M:toggleUI()
 end
 
 function _M:activate()
+	Shader:setDefault("textoutline", "textoutline")
+
 	local size, size_mono, font, font_mono, font_mono_h, font_h
 	if config.settings.tome.fonts.type == "fantasy" then
 		size = ({normal=16, small=14, big=18})[config.settings.tome.fonts.size]
diff --git a/game/modules/tome/data/gfx/shaders/textoutline.lua b/game/modules/tome/data/gfx/shaders/textoutline.lua
index 2becfca846e1701e181621163cbe2100de5ef10b..d8697b80fe96df728c8660d6a6a375c9f7ec5500 100644
--- a/game/modules/tome/data/gfx/shaders/textoutline.lua
+++ b/game/modules/tome/data/gfx/shaders/textoutline.lua
@@ -24,7 +24,7 @@ return {
 		tex = { texture = 0 },
 		textSize = textSize or {1, 1},
 		intensity = intensity or 0.5,
-		outlineSize = outlineSize or {1.5, 1.5},
+		outlineSize = outlineSize or {1, 1},
 		outlineColor = outlineColor or {0, 0, 0, 1},
 	},
 	clone = false,
diff --git a/src/core_lua.c b/src/core_lua.c
index ba48e809936321fe848ec55f1febdbb9671b1f3d..65cd5d54e49d96b6e5ff30b68391d5898b52922f 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -264,10 +264,12 @@ static GLenum sdl_gl_texture_format(SDL_Surface *s) {
 
 // allocate memory for a texture without copying pixels in
 // caller binds texture
+static char *largest_black = NULL;
+static int largest_size = 0;
 void make_texture_for_surface(SDL_Surface *s, int *fw, int *fh, bool clamp) {
 	// Paramétrage de la texture.
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_EDGE : GL_REPEAT);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp ? GL_CLAMP_TO_BORDER : GL_REPEAT);
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp ? GL_CLAMP_TO_BORDER : GL_REPEAT);
 	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
 
 	// get the number of channels in the SDL surface
@@ -285,7 +287,13 @@ void make_texture_for_surface(SDL_Surface *s, int *fw, int *fh, bool clamp) {
 	if (fh) *fh = realh;
 	//printf("request size (%d,%d), producing size (%d,%d)\n",s->w,s->h,realw,realh);
 
-	glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, realw, realh, 0, texture_format, GL_UNSIGNED_BYTE, NULL);
+	if (!largest_black || largest_size < realw * realh * 4) {
+		if (largest_black) free(largest_black);
+		largest_black = calloc(realh*realw*4, sizeof(char));
+		largest_size = realh*realw*4;
+		printf("Upgrading black texture to size %d\n", largest_size);
+	}
+	glTexImage2D(GL_TEXTURE_2D, 0, nOfColors, realw, realh, 0, texture_format, GL_UNSIGNED_BYTE, largest_black);
 
 #ifdef _DEBUG
 	GLenum err = glGetError();