# Sprite Outline via Shader - showcase & looking for improvements

**URL:** <https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375>\
**Category:** Phaser 3\
**Created:** [May 8, 2019, 11:30am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375 "2019-05-08T11:30:15Z")\
**Posts on this page:** 13\
**Page:** 1

<div class="post-metadata">

**Author:** ![jppresents](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/jppresents/32/1266_2.png) [@jppresents](https://phaser.discourse.group/u/jppresents)\
**Post date:** [May 8, 2019, 11:30am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/1 "2019-05-08T11:30:15Z")

</div>

Hey guys,

I am looking into outlining sprites using a shader - I am not an expert on shaders at all.  
I looked around a bit (googlefu) but did not find any already existing solution.

This is what I got so far:

solid color:  
 ![mouseover1](https://global.discourse-cdn.com/free1/uploads/phaser1/original/2X/9/9fb02db20c772c8d2d3155405b55cdf6f06657ae.gif)

alpha color:  
 ![mouseover2](https://global.discourse-cdn.com/free1/uploads/phaser1/original/2X/a/a9756050e4e21593bf6661c10341bbceb53afa46.gif)

slightly more complex shape:  
 ![mouseover3](https://global.discourse-cdn.com/free1/uploads/phaser1/original/2X/a/a7cf86fe452c000713e135e1cc11ccdb78daa2e4.gif)

Here is the shader code:

```
class OutlinePipeline extends Phaser.Renderer.WebGL.Pipelines.TextureTintPipeline {
    constructor(game: Phaser.Game) {
        let config = {game: game,
            renderer: game.renderer,
            fragShader: `
            precision mediump float;
            uniform sampler2D uMainSampler;
            varying vec2 outTexCoord;
            void main(void) {
                vec4 color = texture2D(uMainSampler, outTexCoord);
                vec4 colorU = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y - 0.001));
                vec4 colorD = texture2D(uMainSampler, vec2(outTexCoord.x, outTexCoord.y + 0.001));
                vec4 colorL = texture2D(uMainSampler, vec2(outTexCoord.x + 0.001, outTexCoord.y));
                vec4 colorR = texture2D(uMainSampler, vec2(outTexCoord.x - 0.001, outTexCoord.y));
                
                gl_FragColor = color;
                
                if (color.a == 0.0 && (colorU.a != 0.0 || colorD.a != 0.0 || colorL.a != 0.0 || colorR.a != 0.0) ) {
                    gl_FragColor = vec4(1.0, 0.0, 0.0, .2);
                }
            }`};
        super(config);
    }

```

}

To get this to run:

in create:

```
(<Phaser.Renderer.WebGL.WebGLRenderer>this.game.renderer).addPipeline('outline', new OutlinePipeline(this.game));

```

And to activate / deactivate it on a sprite:

```
this.sprite.setPipeline("outline");

this.sprite.resetPipeline();

```

And here are the problems I am looking for input on 🙂

1. “0.001” is a magic value that works for texture lookup on 1024 x 1024 textures.  
Found it just by trying - there should be a way to get the texture size and calculate this value.

2. The color & alpha are hard coded into the shader - I guess I should have a look on how the tint pipline get’s the values into the shader 🙂

3. When looking up the pixels, at the border we look up pixels of other sprites - for that reason there needs to be padding (at least 1 pixel) on the sprite sheet, I don’t know if this could be restricted to only lookup within the sprite itself.

4. For this to work a 1 pixel transparent border around the picture as part of the sprite is needed. (though I think this is ok and kind of expected)

5. With some tinkering I guess with this method a glow is possible (lookup further out, different alphas)

Feedback or tips on any of the points is very welcome.

---

<div class="post-metadata">

**Author:** ![jcyuan](https://avatars.discourse-cdn.com/v4/letter/j/a3d4f5/32.png) [@jcyuan](https://phaser.discourse.group/u/jcyuan)\
**Post date:** [June 19, 2019, 9:43am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/2 "2019-06-19T09:43:58Z")

</div>

**q1:**  
#extension GL\_OES\_standard\_derivatives : enable  
then  
replace your magic 0.001 with dFdx(outTexCoord) dFdy(outTexCoord)  
BTW:  
`gl_FragColor = color.a * colurU.a * colorD.a * ..... colorR.a == 0. ? color : vec4(1., 0., 0., .2);`  
ternery condition is faster then IF.

**q2:**  
suggest that use 3.17.0, there is native Shader gameobject to use, so no need to deal with the renderer.

**q3:**  
texturepacker provides such functionality for you, why not use it? shader is still a resource we need to save… 🙂 if you mean your texture is an atlas, then  
outTexCoord \*= frameSize / resolution  
outTexCoord += framePosition / resolution

**q4:**  
of course, OpenGL even renders gaps if you donot pad some transparent pixels between image blocks.

**q5:**  
another topic though…

---

<div class="post-metadata">

**Author:** ![jppresents](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/jppresents/32/1266_2.png) [@jppresents](https://phaser.discourse.group/u/jppresents)\
**Post date:** [June 19, 2019, 3:06pm UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/3 "2019-06-19T15:06:29Z")

</div>

Thank you for the Feedack @jcyuan!

Can you point me to an example or a short code snipped or documentation how to use a native shader object in 3.17.0?

---

<div class="post-metadata">

**Author:** ![jcyuan](https://avatars.discourse-cdn.com/v4/letter/j/a3d4f5/32.png) [@jcyuan](https://phaser.discourse.group/u/jcyuan)\
**Post date:** [June 20, 2019, 3:20am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/4 "2019-06-20T03:20:54Z")

</div>

that’s quite easy:

```
// in preload method
this.load.glsl("myGlsl", "external_glsl_file.glsl");

// then in create method
const obj = this.add.shader("myGlsl");
obj.setSampler2D(...); // or shortcut methods: setChannel0 / setChannel1 ... setChannel3
obj.setUniform(...);

// and then just treat this obj as an image to use, even add it into a container...

```

and, in your glsl, there are built-in uniforms:

```
uniform sampler2D iChannel0;
uniform sampler2D iChannel1;
uniform sampler2D iChannel2;
uniform sampler2D iChannel3;
uniform float sampleRate;
uniform vec4 date;
uniform vec2 mouse;
uniform float time;
uniform vec2 resolution;

```

docs ref:  
[https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Shader.html](https://photonstorm.github.io/phaser3-docs/Phaser.GameObjects.Shader.html)

---

<div class="post-metadata">

**Author:** ![alleycat](https://avatars.discourse-cdn.com/v4/letter/a/77aa72/32.png) [@alleycat](https://phaser.discourse.group/u/alleycat)\
**Post date:** [February 19, 2020, 3:11am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/5 "2020-02-19T03:11:57Z")

</div>

interesting … shader objects native, i blink and it gets 20 more options. Not up to me to tell people how to do what as for one im just a rank amateur hobbyist. Ever since ive seen the shadertoy website coming up on [pouet.net](http://pouet.net) glsl has been winking but far from there. In this case, phaser being pretty hungry already i think id just add an extra frame to the spritesheet which (i think) would in the end take up less resources than a ‘subroutine’ (pardon my archaic) calculating one.

**ofcourse** i do agree : doing it with a shader is lot more pretty (code-wise) but the client/player/user in the end will notice nothing but maybe the amount of cpu used on the device it runs on … mighty interesting though …

---

<div class="post-metadata">

**Author:** ![hcakar](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/hcakar/32/459_2.png) [@hcakar](https://phaser.discourse.group/u/hcakar)\
**Post date:** [August 20, 2020, 4:34pm UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/6 "2020-08-20T16:34:03Z")

</div>

Hey @jppresents,

Could you actually finish this as shader?

And if it is could you be sooo kind and share the glsl? 😃

If not is there some source that i can learn about this `fragShader` ?

Thanks

---

<div class="post-metadata">

**Author:** ![jppresents](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/jppresents/32/1266_2.png) [@jppresents](https://phaser.discourse.group/u/jppresents)\
**Post date:** [August 21, 2020, 7:29pm UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/7 "2020-08-21T19:29:08Z")

</div>

This is what I ended up using, be aware that this was for phaser 3.16.2 and used some magic numbers as you can see. I think shader pipelines have changed since then.

> <https://gist.github.com/jppresents/8131d44120972dbe01642304824c6999>

---

<div class="post-metadata">

**Author:** ![rexrainbow](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/rexrainbow/32/51_2.png) [@rexrainbow](https://phaser.discourse.group/u/rexrainbow)\
**Post date:** [August 22, 2020, 2:39am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/8 "2020-08-22T02:39:02Z")

</div>

I have an outline effect shader game object

- [Demo](https://codepen.io/rexrainbow/pen/abdpPMb)
- [Document](https://rexrainbow.github.io/phaser3-rex-notes/docs/site/effectlayer-outline/)
- [GLSL code](https://github.com/rexrainbow/phaser3-rex-notes/blob/master/plugins/gameobjects/effectlayer/outline/outline-frag.js), which modified from [pixi-filters](https://github.com/pixijs/pixi-filters/blob/master/filters/outline/src/outline.frag)

This plugin can’t work with p3.50 yet.

---

<div class="post-metadata">

**Author:** ![dragoonzx](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/dragoonzx/32/4844_2.png) [@dragoonzx](https://phaser.discourse.group/u/dragoonzx)\
**Post date:** [February 22, 2021, 9:05am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/9 "2021-02-22T09:05:44Z")

</div>

That`s what i have [OutlinePipeline (forked) - CodeSandbox](https://codesandbox.io/s/outlinepipeline-forked-o1jgo)  
something like violet square on black background…

---

<div class="post-metadata">

**Author:** ![dragoonzx](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/dragoonzx/32/4844_2.png) [@dragoonzx](https://phaser.discourse.group/u/dragoonzx)\
**Post date:** [February 22, 2021, 9:05am UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/10 "2021-02-22T09:05:46Z")

</div>

Are there any updates?  
Want to make it work with version \>= 3.5

Now I have error:  
.WebGL-0x7fd99580aa00]GL ERROR :GL\_INVALID\_OPERATION : glUniform1iv: count \> 1 for non-array

---

<div class="post-metadata">

**Author:** ![rexrainbow](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/rexrainbow/32/51_2.png) [@rexrainbow](https://phaser.discourse.group/u/rexrainbow)\
**Post date:** [February 22, 2021, 2:19pm UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/11 "2021-02-22T14:19:28Z")

</div>

[Here](https://rexrainbow.github.io/phaser3-rex-notes/docs/site/shader-outline/) is another outline post fx shader plugin, worked for \>= phaser3.50.

[Demo](https://codepen.io/rexrainbow/pen/dyGNrqa)

- Pointer-over and pointer-out any sprite

---

<div class="post-metadata">

**Author:** ![ising4u](https://yyz2.discourse-cdn.com/free1/user_avatar/phaser.discourse.group/ising4u/32/9100_2.png) [@ising4u](https://phaser.discourse.group/u/ising4u)\
**Post date:** [September 12, 2025, 3:52pm UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/12 "2025-09-12T15:52:35Z")

</div>

Nice work! Clap 100x times!

---

<div class="post-metadata">

**Author:** ![Markaram81](https://avatars.discourse-cdn.com/v4/letter/m/ecb155/32.png) [@Markaram81](https://phaser.discourse.group/u/Markaram81)\
**Post date:** [September 18, 2025, 2:12pm UTC](https://phaser.discourse.group/t/sprite-outline-via-shader-showcase-looking-for-improvements/2375/13 "2025-09-18T14:12:13Z")

</div>

It seems like the hardcoded color values could be replaced with uniforms, similar to how tint pipelines pass colors into shaders. That way, the outline color and alpha could be controlled at runtime without modifying the shader each time.
