Is there a way to give a sprite an outline?

  • I’d like to give a sprite a glowing outline when they get healed/damaged/whatever but I can’t think of a way to code this using the 2d canvas. If it were possible, I’d think it would be a global composite operation, but I can’t think of a way to achieve it with one of them.

    I did find this stackoverflow answer that recommends creating a fatter, solid color version of the original and put the original on top of it. That would give it an outline, but it seems like a lot of extra work especially considering I’m using placeholder art. Is there an easier way?

    FWIW, I don’t mind if the outline creates a wider border or keeps the sprite the same size, I just want the outline look.

  • @tieTYT Hi!
    You’ll need to create the sprite’s new outlined image yourself and display it when the sprite’s state changes.
    The Canvas Drawing API doesn’t have tools that can do that for you.

  • LDG

    I think the method that was described on stackoverflow could be accomplished dynamically. Here’s how I’d do it:

    • Draw sprite to a buffer at a slightly larger scale, something like 110% of original size. Larger for a thicker outline.
    • Next, fill the buffer with the solid color you want for the outline color using the “source-in” composite mode (This will fill just the area of the sprite with a solid color)
    • Render the original sprite at the original size to the buffer
    • Lastly, render the buffer to the main canvas wherever you want

    I think that should produce the effect you want with the benefit of not having to create extra images AND it’ll continue to work just fine as the graphics change. The only really tricky part will be sizing the buffer correctly account for the outline.

    If I have some time I might make a proof concept because this sounds fun and useful.

  • LDG

    Sooo, it seems like my method sorta works. Scaling the sprite doesn’t always produce the best outline, however. I threw my code into a repo on GitHub. Here’s the relevant JavaScript.

    And this is the result of the dynamic outline:

    As you can see, it’s not perfect. Another approach might be to loop over the canvas bitmap data and set pixels based on their neighbors. e.g. For every transparent pixel with at least one non-transparent neighbor, set to outline color. Repeat N times for larger outlines.

  • LDG

    I made a second attempt with more mixed results! My new method uses image pixel manipulation. Specifically, it draws an outline pixel whenever it detects a transparent pixel with at least one neighboring non-transparent pixel. Here’s the source of this method.

    You can see the methods side-by-side here. The second method (on the right) traces the shape of the sprite more accurately than the first method, but is much rougher around the edges. I suspect this could be cleaned up with some kind of blurring algorithm. Also, this method is probably slower than the first due to looping over the pixel data so much.

  • @geoffb Nice, that is an interesting technique. Visually, the left side looks nicer, but there are some problems with it: His left arm isn’t completely outlined. Maybe it’s just not perfect centering. There’s more outline below than above, I think.

    Either way, thanks a lot for the ideas.

  • Penguin

    Late to the party, but wanted to ask a clarification anyway. I thought @tieTYT 's original question meant something more “glowing” than “outlining”. (I know he said glowing outline, but hear me out.) What I thought he meant was more akin to the lamps glowing in AWL. If I’m totally off, I’ll show myself out :)

  • LDG

    @tieTYT said:

    Visually, the left side looks nicer, but there are some problems with it: His left arm isn’t completely outlined. Maybe it’s just not perfect centering. There’s more outline below than above, I think.

    Yeah, I think that’s just a drawback of that particular approach since it’s sort of a hack. Scaling up changes the position of the arms in ways that different centering cannot fix.

    My quick and dirty second approach doesn’t look great, but seems like it could be improved by tweaking the alpha values of the edges or with smarter pixel placement.

    Anyway, it was a fun little experiment and definitely a harder problem to solve than I first thought.

  • Patron

    Hey guys, I’ve just developed another way to do this.

    It works by drawing a circle with a 2 pixel radius centered on each non-transparent pixel of the sprite, using the destination-over composition.

    It looks better than Geoff’s second approach, but still jaggier than the first:

    And tho it works fine with solid sprites, any sprites with transparent “gaps” will look horrible. Also, most low-rez sprites will look weird.

    It might work for this kind of cartoony sprite, tho.

  • It’s not exactly what you’re looking for but there’s also this technique of using a fat shadow:

Log in to reply