diff --git a/game/modules/tome/class/Actor.lua b/game/modules/tome/class/Actor.lua
index 81dfd09a065fc54fba8c15e8b9a222f9847903eb..70f4dccb5a0232f754c6c88243deb0cf7d305623 100644
--- a/game/modules/tome/class/Actor.lua
+++ b/game/modules/tome/class/Actor.lua
@@ -4253,7 +4253,7 @@ function _M:canSeeNoCache(actor, def, def_pct)
 	end
 
 	-- Check for invisibility. This is a "simple" checkHit between invisible and see_invisible attrs
-	if actor:attr("invisible") then
+	if actor:attr("invisible") and actor ~= self then
 		-- Special case, 0 see invisible, can NEVER see invisible things
 		local def = self:combatSeeInvisible()
 		if def <= 0 then return false, 0 end
diff --git a/game/modules/tome/data/gfx/shaders/invis_edge.frag b/game/modules/tome/data/gfx/shaders/invis_edge.frag
new file mode 100644
index 0000000000000000000000000000000000000000..cc25f4a422f20a6b385cc2fc5d7e65b272c55278
--- /dev/null
+++ b/game/modules/tome/data/gfx/shaders/invis_edge.frag
@@ -0,0 +1,45 @@
+uniform sampler2D tex;
+uniform float tick;
+uniform vec4 color1;
+uniform vec4 color2;
+
+float avg_intensity(vec4 pix) {
+	return pix.a;
+}
+
+vec4 get_pixel(vec2 coords, float dx, float dy) {
+	return texture2D(tex,coords + vec2(dx, dy));
+}
+
+// returns pixel color
+float IsEdge(in vec2 coords){
+	float dxtex = 0.5 /float(textureSize(tex,0)) ;
+	float dytex = 0.5 /float(textureSize(tex,0));
+	float pix[9];
+	int k = -1;
+	float delta;
+
+	// read neighboring pixel intensities
+	for (int i=-1; i<2; i++) {
+		for(int j=-1; j<2; j++) {
+			k++;
+			pix[k] = avg_intensity(get_pixel(coords, float(i)*dxtex, float(j)*dytex));
+		}
+	}
+
+	// average color differences around neighboring pixels
+	delta = (abs(pix[1]-pix[7])+
+		abs(pix[5]-pix[3]) +
+		abs(pix[0]-pix[8])+
+		abs(pix[2]-pix[6])
+		)/4.;
+
+	return clamp(5.5*delta,0.0,1.0);
+}
+
+void main(void)
+{
+	float edg = IsEdge(gl_TexCoord[0].xy);
+	gl_FragColor = mix(color1, color2, sin(edg + tick/1000 + gl_TexCoord[0].y));
+	gl_FragColor.a = edg;
+}
diff --git a/game/modules/tome/data/gfx/shaders/invis_edge.lua b/game/modules/tome/data/gfx/shaders/invis_edge.lua
new file mode 100644
index 0000000000000000000000000000000000000000..ee52892f1cd4ddebecd2538c5f8a12a291ecda31
--- /dev/null
+++ b/game/modules/tome/data/gfx/shaders/invis_edge.lua
@@ -0,0 +1,28 @@
+-- ToME - Tales of Maj'Eyal
+-- Copyright (C) 2009, 2010, 2011, 2012, 2013 Nicolas Casalini
+--
+-- This program is free software: you can redistribute it and/or modify
+-- it under the terms of the GNU General Public License as published by
+-- the Free Software Foundation, either version 3 of the License, or
+-- (at your option) any later version.
+--
+-- This program is distributed in the hope that it will be useful,
+-- but WITHOUT ANY WARRANTY; without even the implied warranty of
+-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+-- GNU General Public License for more details.
+--
+-- You should have received a copy of the GNU General Public License
+-- along with this program.  If not, see <http://www.gnu.org/licenses/>.
+--
+-- Nicolas Casalini "DarkGod"
+-- darkgod@te4.org
+
+return {
+	frag = "invis_edge",
+	vert = nil,
+	args = {
+		color1 = {0, 0, 1, 1},
+		color2 = {0, 0.5, 0.9, 1},
+	},
+	clone = false,
+}
diff --git a/game/modules/tome/data/talents/celestial/eclipse.lua b/game/modules/tome/data/talents/celestial/eclipse.lua
index 46767ce57d4eddfabf15825bfd8aae9c07a1f32f..8bfafacccf9c6d696b520176846917d0e0949296 100644
--- a/game/modules/tome/data/talents/celestial/eclipse.lua
+++ b/game/modules/tome/data/talents/celestial/eclipse.lua
@@ -157,10 +157,22 @@ newTalent{
 			pstop = self:addTemporaryValue("positive_at_rest_disable", 1),
 			nstop = self:addTemporaryValue("negative_at_rest_disable", 1),
 		}
+		if not self.shader then
+			ret.set_shader = true
+			self.shader = "invis_edge"
+			self.shader_args = {color1={1,1,0,1}, color2={0,0,0,1}}
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 		self:resetCanSeeCacheOf()
 		return ret
 	end,
 	deactivate = function(self, t, p)
+		if p.set_shader then
+			self.shader = nil
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 		self:removeTemporaryValue("invisible", p.invisible)
 		self:removeTemporaryValue("invisible_damage_penalty", p.invisible_damage_penalty)
 		self:removeTemporaryValue("positive_regen_ref", p.fill)
diff --git a/game/modules/tome/data/talents/spells/phantasm.lua b/game/modules/tome/data/talents/spells/phantasm.lua
index cf1556d9625b7b44c45712bee32f1477f2a4ba96..07f85c5f7b28a2522255e21f083bb14e26084f51 100644
--- a/game/modules/tome/data/talents/spells/phantasm.lua
+++ b/game/modules/tome/data/talents/spells/phantasm.lua
@@ -145,10 +145,21 @@ newTalent{
 			invisible_damage_penalty = self:addTemporaryValue("invisible_damage_penalty", 0.7),
 			drain = self:addTemporaryValue("mana_regen", -2),
 		}
+		if not self.shader then
+			ret.set_shader = true
+			self.shader = "invis_edge"
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 		self:resetCanSeeCacheOf()
 		return ret
 	end,
 	deactivate = function(self, t, p)
+		if p.set_shader then
+			self.shader = nil
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 		self:removeTemporaryValue("invisible", p.invisible)
 		self:removeTemporaryValue("invisible_damage_penalty", p.invisible_damage_penalty)
 		self:removeTemporaryValue("mana_regen", p.drain)
diff --git a/game/modules/tome/data/timed_effects/magical.lua b/game/modules/tome/data/timed_effects/magical.lua
index aec61b516c8610a145873caa460ec66de1928e9a..9b8a190026b00b8e88573f93faf0a87af413864a 100644
--- a/game/modules/tome/data/timed_effects/magical.lua
+++ b/game/modules/tome/data/timed_effects/magical.lua
@@ -206,8 +206,19 @@ newEffect{
 			eff.regenid = self:addTemporaryValue("no_life_regen", 1)
 			eff.healid = self:addTemporaryValue("no_healing", 1)
 		end
+		if not self.shader then
+			eff.set_shader = true
+			self.shader = "invis_edge"
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 	end,
 	deactivate = function(self, eff)
+		if eff.set_shader then
+			self.shader = nil
+			self:removeAllMOs()
+			game.level.map:updateMap(self.x, self.y)
+		end
 		self:removeTemporaryValue("invisible", eff.tmpid)
 		self:removeTemporaryValue("invisible_damage_penalty", eff.penaltyid)
 		if eff.regen then