Retro CRT distortion effect in Flixel 2.5

A couple of weeks ago I started using the Flixel Framework, a set of class and libraries in ActionScript3 to effectively design videogames in Flash. Flixel is suggested to all the programmers who want to create games with a retro-style flavour. Although there is a huge support community that actively works on Flixel, finding the right effect is not always easy. After looking for few hours desperately trying to find a way to implement a CRT distortion effect, I decided to create it myself! The result is a class called “RetroEffect“.

The inspiration for this work comes from a great article by Cadin Batrack, called  “Create a retro CRT distortion effect using RGB shifting“. Although, the version I create is integrated to Flixel 2.5, and has several performance improvements that makes is lighter to execute with a high framerate. In old CRT monitors, the image is composite using three different colour layers. When they are not perfectly synchronised, the result is something like this one:

Retro CRT distortion effect by Cadin Batrack

The way this effect is implemented consists in extracting the red, green and blue channel from the original image and re-drawing them a little bit distorted. The solution proposed by Cadin Batrack uses the Tweener library. Despite its being really effective, is also extremely heavy and its usage is not advisable where performance should be an issue. I used a very light version that simply cause the channel to “oscillate” following a sinusoidal path. The effect does not reach the same yeah-yeah level of awesomeness, but it can be a good base for further versions.

The code that does the trick is;

[sourcecode language=”as3″]
&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
// Red channel ——————————————&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.fillRect(source.rect, 0xFF000000);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.copyChannel&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
(   source, source.rect, _zeroPoint,&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
BitmapDataChannel.RED, BitmapDataChannel.RED );&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_bitmap.alpha = randRange(8, 10) / 10;&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;_distortion.a = sinusoid(_counter + 0 / 5, 0.99, 1.00 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_distortion.d = sinusoid(_counter + 2 / 5, 1, 1.01 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_output.draw(_bitmap, _distortion, null, null, null, true);&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;// Green channel ——————————————&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.fillRect(source.rect, 0xFF000000);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.copyChannel&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
(   source, source.rect, _zeroPoint,&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_bitmap.alpha = randRange(8, 10) / 10;&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;_distortion.a = sinusoid(_counter + 1 / 5, 0.99, 1.00 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_distortion.d = sinusoid(_counter + 1 / 5, 1, 1.01 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_output.draw(_bitmap, _distortion, null, BlendMode.SCREEN, null, true);&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;// Blue channel ——————————————&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.fillRect(source.rect, 0xFF000000);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_buffer.copyChannel&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
(   source, source.rect, _zeroPoint,&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
BitmapDataChannel.BLUE, BitmapDataChannel.BLUE );&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_bitmap.alpha = randRange(8, 10)/10;&amp;lt;/p&amp;gt;&lt;br /&gt;<br />
&amp;lt;p&amp;gt;_distortion.a = sinusoid(_counter + 2 / 5, 0.99, 1.00 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_distortion.d = sinusoid(_counter + 0 / 5, 1, 1.01 , 0.5);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
_output.draw(_bitmap, _distortion, null, BlendMode.SCREEN, null, true);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
[/sourcecode]

Colour channels are copied into “_buffer“, and all the drawing operations are made into a temporary “BitmapData” called “_output“. The sinusoid curve is feed with a counter “_counter” that indicates the number of seconds elapsed from the beginning of the game. You can play with the matrix parameters to obtain different types of effects.

The usage of this class is quite easy. It must be added as a normal sprite, specifying the camera that will be rendered with the retro CRT distortion effect. In the example below, the standard camera has been used.

[sourcecode language=”as3″]&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
var retroEffect : RetroEffect = new RetroEffect(FlxG.camera);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
add(retroEffect);&amp;lt;br /&amp;gt;&lt;br /&gt;<br />
[/sourcecode]

You can download the “RetroEffect” class compatible with Flixel 2.5 from here.

Comments

14 responses to “Retro CRT distortion effect in Flixel 2.5”

  1. The practical obstacle is not merely creating a CRT-style effect but locating the right implementation within a large community ecosystem. Retro visuals often depend on small choices in distortion, scanlines, color bleed, and timing, so a focused explanation of each parameter can be more useful than a finished snippet alone. That context also makes it easier to adapt the technique to a different game aesthetic.

  2. Retro CRT effects are a fun way to give games a classic look inspired by old television screens. Techniques like screen distortion can add nostalgia and personality to a project while helping developers experiment with different visual styles.

  3. The article captures an early practical challenge in retro-style development: a framework can make game construction approachable while still leaving developers to hunt for a specific visual effect. That distinction matters, because the CRT look is not merely decoration; it shapes how players read motion, contrast, and screen artifacts. The active community mentioned here can reduce that search burden, but examples that isolate each distortion parameter would make the approach more reusable for valenciano projects too.

  4. Convert any PDF to dark mode in your browser. Photos keep their original colors. No upload, no signup, free. Open source.

  5. AWESOME! I’m gonna use this baby for sure. True, Batrack’s looks prettier, more random and broken, while yours is one same pattern over and over again. But I’m using this just for 1 second, every five seconds or so, and it looks GORGEOUS.

  6. Convert any PDF to dark mode in your browser. Photos keep their original colors. No upload, no signup, free. Open source.

  7. For people turning reports, research notes, or documentation into reusable web content, the main concern is often what happens to the file after conversion. PDFtoMDConverter addresses that practical gap by keeping the process in the browser, avoiding account creation and application-server uploads. Editable Markdown is especially useful when a PDF needs restructuring, citation cleanup, or publication in a knowledge base rather than simply being copied as plain text. Clear scan support also makes the tool relevant for archived documents that still need a workable text format.

  8. A useful symbol collection should make selection easier, not turn a short bio into a formatting project. Grouping characters by mood and use case helps people compare options quickly, especially when they need a subtle separator, a recognizable marker, or a compact accent. bio symbols work best when they support the words already there and do not make a profile harder to read, copy, or understand at a glance.

  9. A simple online timer can be more useful when it removes the usual distractions: account creation, advertising, and complicated settings. Support for hours, minutes, and seconds makes it suitable for focused work, study sessions, cooking, exercise, or short breaks. Start, pause, resume, and reset controls cover the essential workflow, while an end sound lets people step away from the screen. A clean browser interface also makes the tool easier to use across different devices.

  10. Using an approximation sign well is partly a communication decision. Readers should be able to tell whether a number was rounded, estimated, measured, or derived from a model. A short note about precision can be more informative than adding extra decimal places. In typeset work, LaTeX approximately equal notation is especially useful when the same expression must remain clear in articles, slides, and reproducible source files without depending on manual formatting.

    1. For people turning reports, research notes, or documentation into reusable web content, the main concern is often what happens to the file after conversion. PDF to dark modeaddresses that practical gap by keeping the process in the browser, avoiding account creation and application-server uploads. Editable Markdown is especially useful when a PDF needs restructuring, citation cleanup, or publication in a knowledge base rather than simply being copied as plain text. Clear scan support also makes the tool relevant for archived documents that still need a workable text format.

  11. David T. Marchand avatar
    David T. Marchand

    Thanks! I already looked for it when I saw I needed it to run this. It looks good, a very simple project can really improve its looks so much with just a little effect like this.

  12. David T. Marchand avatar
    David T. Marchand

    AWESOME! I’m gonna use this baby for sure. True, Batrack’s looks prettier, more random and broken, while yours is one same pattern over and over again. But I’m using this just for 1 second, every five seconds or so, and it looks GORGEOUS.

    One thing: I had to add the randRange function, is there a reason why you didn’t put it in the class? Not complaining or anything, it’s just this one detail that would make this class really copy-paste-use.

  13. Francesco avatar

    😉

Leave a Reply

Your email address will not be published. Required fields are marked *