LogoLogo
  • Home
  • Projects
  • About
  • Contact

Liquid Text Effect

Devon O. · July 14, 2010 · Actionscript · 3 comments
4

Haven’t been too active around here lately due to a major on going project at work lately as well as the fact that my wife and I are in the slow process of moving homes. Really, the only free time it seems I have these days is during the lunch hour. So, over the past two days, I came up with this fun little toy during lunches.

Having recently re-watched Terminator 2 or 3 or 4 or whichever one had that liquid metal dude, I wanted to do something liquid metally. And below is the text effect result. You can change what it says by typing something new into the text box and clicking the “change” button. You can also try different colors using the color picker in the top left (a deep red blood color may be cool for halloween, a blue for nice looking water or black can create a nice new oily BP logo). You can also mouse over the text to swish it up a bit.

Get Adobe Flash player

The code is by no means optimized or even cleaned up, but if you’d like to play around, it’s all below. To use as is, you’ll need the Arial Black font and the great minimalcomps from Keith (Bit-101) Peters.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
package  {
    
    import com.bit101.components.ColorChooser;
    import com.bit101.components.InputText;
    import com.bit101.components.PushButton;
    import com.bit101.components.Style;
    import flash.utils.setTimeout;
    
    import com.greensock.easing.Quad;
    import com.greensock.TweenLite;
    
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Sprite;    
    import flash.events.Event;
    import flash.events.MouseEvent;    
    import flash.filters.BevelFilter;
    import flash.filters.BlurFilter;
    import flash.filters.DropShadowFilter;
    import flash.geom.Point;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    import flash.text.TextFormat;
 
    /**
     * some liquidy metal madness
     * @author Devon O.
     */
    
     [SWF(width='640', height='400', backgroundColor='#444444', frameRate='40')]
    public class Main extends Sprite {
        
        [Embed(source = "../assets/ariblk.ttf", fontFamily = "ariblk", mimeType = "application/x-font", embedAsCFF = "false")] public static const EFONT:Class;
        public static const NUM_BLOBS:int = 500;
        public static const PROXIMITY:int = 35;
        
        private var _holder:Sprite = new Sprite();
        
        private var _display:BitmapData;
        
        private var _textData:BitmapData;
        private var _text:TextField;
        private var _textHolder:Sprite;
        
        private var _textColor:uint = 0xFF333333;
        
        private var _blobs:Vector.<Circle> = new Vector.<Circle>(NUM_BLOBS, true);
        private var _toPoints:Vector.<SimplePoint> = new Vector.<SimplePoint>(NUM_BLOBS, true);
        
        private var _layout:BitmapLayout;
        
        private var _blur:BlurFilter = new BlurFilter(8, 8, 5);
        private var _bevel:BevelFilter = new BevelFilter(4, 80, 0xFFFFFF, 1, 0x111111, 1, 8, 8, 2, 1);
        private var _shadow:DropShadowFilter = new DropShadowFilter(4, 80, 0x000000, 1, 4, 4, 1, 1, false, false);
        private var _pt:Point = new Point();
        
        private var _colorPicker:ColorChooser;
        private var _input:InputText;
        private var _enterButton:PushButton;
        
        public function Main() {
            init();
        }
        
        private function init():void {
            initText();
            setText("LIQUID");
            
            initDisplay();
            initBalls();
            
            initUI();
            
            addEventListener(Event.ENTER_FRAME, drawDisplay);
        }
        
        private function initDisplay():void {
            _display = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000);
            var view:Bitmap = new Bitmap(_display);
            view.filters = [_bevel, _shadow];
            addChild(view);
        }
        
        private function initUI():void {
            Style.BUTTON_FACE = 0x333333;
            
            _colorPicker = new ColorChooser(this, 10, 10, 0x333333, colorHandler);
            _colorPicker.usePopup = true;
            
            _input = new InputText(this, _colorPicker.x + _colorPicker.width + 10, 10, "LIQUID");
            
            _enterButton = new PushButton(this, _input.x + _input.width + 10, 10, "CHANGE", swapText);
        }
        
        private function colorHandler(event:Event):void {    
            var r:uint = _colorPicker.value >> 16;
            var g:uint = _colorPicker.value >> 8 & 0xFF;
            var b:uint = _colorPicker.value & 0xFF;
            _textColor = 0xFF << 24 | r << 16 | g << 8 | b;
        }
        
        private function initBalls():void {
            for (var i:int = 0; i < NUM_BLOBS; i++) {
                var b:Circle = new Circle();
                var pt:SimplePoint = _layout.getPoint();
                b.cx = b.tx = b.x = pt.x;
                b.cy = b.ty = b.y = pt.y;
                b.range = randRange(2, 1, 2);
                b.angle = randRange(360, 0);
                b.speed = randRange(.13, .05, 2);
                b.scaleX = b.scaleY = randRange(1, .5, 2);
                _blobs[i] = b;
                _toPoints[i] = new SimplePoint(b.cx + randRange(150, -150), b.cy + randRange(150, -150));
                _holder.addChild(b);
            }
        }
        
        private function initText():void {
            _text = new TextField();
            _text.defaultTextFormat = new TextFormat(new EFONT().fontName, 150, 0x000000);
            _text.autoSize = TextFieldAutoSize.LEFT;
            _text.embedFonts = true;
            _textHolder = new Sprite();
            _textHolder.addChild(_text);
            _textData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x00000000);
        }
        
        private function swapText(event:MouseEvent):void {    
            var i:int = NUM_BLOBS;
            while (i--) {
                if (i == 0) {
                    TweenLite.to(_blobs[i], .60, { x:_toPoints[i].x, y:_toPoints[i].y, ease:Quad.easeOut, onComplete:completeText } );
                } else {
                    TweenLite.to(_blobs[i], .60, { x:_toPoints[i].x, y:_toPoints[i].y, ease:Quad.easeOut } );
                }
            }
        }
        
        private function completeText():void {
            setText(_input.text);
            
            setTimeout(tweenBack, 200);
        }
        
        private function tweenBack():void {
            var i:int = NUM_BLOBS;
            while (i--) {
                var b:Circle = _blobs[i];
                var pt:SimplePoint = _layout.getPoint();
                b.cx = pt.x;
                b.cy = pt.y;
                b.range = randRange(2, 1, 2);
                b.angle = randRange(360, 0);
                b.speed = randRange(.13, .05, 2);
                TweenLite.to(b, .80, { x:b.cx, y:b.cy, ease:Quad.easeOut } );
            }
        }
        
        private function setText(words:String):void {
            _text.text = words;
            _text.x = (stage.stageWidth - _text.width) >> 1;
            _text.y = (stage.stageHeight - _text.height) >> 1;
            
            _textData.fillRect(_textData.rect, 0x00000000);
            _textData.draw(_textHolder);
            
            if (_layout == null) _layout = new BitmapLayout(_textData);
            else _layout.data = _textData;
        }
        
        private function shimmy():void {
            var i:int = NUM_BLOBS;
            while (i--) {
                var b:Circle = _blobs[i];
            
                b.inner.x =  Math.sin(b.angle) * (b.range);
                b.inner.y =  Math.cos(b.angle) * (b.range * 6);
            
                b.angle += b.speed;
                
                var p1:SimplePoint = new SimplePoint(b.cx, b.cy);
                var p2:SimplePoint = new SimplePoint(stage.mouseX, stage.mouseY);
                
                var d:Number = getDist(p1, p2);
                if ( d < (PROXIMITY * PROXIMITY) ) {
                    b.tx = stage.mouseX;
                    b.ty = stage.mouseY
                } else {
                    b.tx = b.cx;
                    b.ty = b.cy;
                }
                b.x += (b.tx - b.x) * .25;
                b.y += (b.ty - b.y) * .25;
            }
        }
        
        private function getDist(p1:SimplePoint, p2:SimplePoint):Number {
            return (p2.x - p1.x) * (p2.x - p1.x) + (p2.y - p1.y) * (p2.y - p1.y);
        }
        
        private function drawDisplay(event:Event):void {
            shimmy();
            
            _display.fillRect(_display.rect, 0x000000);
            _display.draw(_holder);
            _display.applyFilter(_display, _display.rect, _pt, _blur);
            _display.threshold(_display, _display.rect, _pt, ">",  0x001F0000, _textColor, 0x00FF0000, false);
        }
        
        private function randRange(max:Number, min:Number = 0, decimals:int = 0):Number {
            if (min > max) return NaN;
            var rand:Number = Math.random() * (max-min + Math.pow(10, -decimals)) + min;
            return int(rand * Math.pow(10, decimals)) / Math.pow(10, decimals);
        }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package  {
    
    import flash.display.Shape;
    import flash.display.Sprite;
    
    public class Circle extends Sprite {
        
        private var _cx:Number;
        private var _cy:Number;
        private var _tx:Number;
        private var _ty:Number;
        private var _range:Number;
        private var _speed:Number;
        private var _angle:Number;
        private var _inner:Shape = new Shape();
        
        public function Circle() {
            _inner.graphics.beginFill(0xFFFFFF);
            _inner.graphics.drawCircle(0, 0, 6);
            _inner.graphics.endFill();
            addChild(_inner);
        }
        
        public function get cx():Number { return _cx; }
        
        public function set cx(value:Number):void {
            _cx = value;
        }
        
        public function get cy():Number { return _cy; }
        
        public function set cy(value:Number):void {
            _cy = value;
        }
        
        public function get range():Number { return _range; }
        
        public function set range(value:Number):void {
            _range = value;
        }
        
        public function get speed():Number { return _speed; }
        
        public function set speed(value:Number):void {
            _speed = value;
        }
        
        public function get angle():Number { return _angle; }
        
        public function set angle(value:Number):void {
            _angle = value;
        }
        
        public function get inner():Shape { return _inner; }
        
        public function get tx():Number { return _tx; }
        
        public function set tx(value:Number):void {
            _tx = value;
        }
        
        public function get ty():Number { return _ty; }
        
        public function set ty(value:Number):void {
            _ty = value;
        }
    }
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package  {
    
    import flash.display.BitmapData;
 
    public class BitmapLayout {
        
        private var _data:BitmapData;
        
        public function BitmapLayout(data:BitmapData) {
            _data = data;
        }
        
        // tip of the hat to the HYPE framework cats for this bit
        public function getPoint():SimplePoint {
            var pt : SimplePoint;
            
            do {
                pt = new SimplePoint();
                pt.x = (Math.random() * _data.width);
                pt.y = (Math.random() * _data.height);
                
                var c:uint = _data.getPixel32(pt.x, pt.y);
                
                var alpha:uint = c >> 24;
                
                if (alpha == 0) pt = null;
 
                
            } while (pt == null);
            
            return pt;
        }
        
        public function get data():BitmapData { return _data; }
        
        public function set data(value:BitmapData):void {
            _data = value;
        }
    }
 
}
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package  {
 
    public class SimplePoint {
        
        private var _x:Number;
        private var _y:Number;
        
        public function SimplePoint(x:Number = 0, y:Number = 0 ) {
            _x = x;
            _y = y;
        }
        
        public function get x():Number { return _x; }
        
        public function set x(value:Number):void {
            _x = value;
        }
        
        public function get y():Number { return _y; }
        
        public function set y(value:Number):void {
            _y = value;
        }
    }
}
  Facebook   Pinterest   Twitter   Google+
liquidtext effect
  • Adding Flash/Actionscript Content to a Flex Project
    March 29, 2008 · 0 comments
    1837
    1
    Read more
  • Game Timer Download
    January 02, 2010 · 6 comments
    5363
    7
    Read more
  • Starling ‘God Ray’ Filter
    March 10, 2013 · 22 comments
    7135
    16
    Read more
3 Comments:
  1. Awesome effect man, I love playing with it.
    Sort of rediscovered your blog again today after not having visited it for a while. Lots of awesome new experiments!! Thnx for sharing the knowledge, keep it up!

    Hendrik · July 17, 2010
  2. Hey Hendrik, Thanks for the nice comment – and welcome back..

    Devon O. · July 17, 2010
  3. Devon, love your humor:
    1) “re-watched Terminator 2 or 3 or 4 or whichever one had that liquid metal dude”.
    2) “a nice new oily BP logo”.

    Besides from that, impressive what you are capable of in your lunch-breaks, love it!

    Felix

    Felix Sanchez · August 09, 2010

Leave a Comment! Cancel reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Devon O. Wolfgang

AIR | Unity3D | AR/VR

Unity Certified Developer

Technical Reviewer of “The Essential Guide to Flash CS4 AIR Development” and “Starling Game Development Essentials”

Reviewer of “The Starling Handbook”

Unity Engineer at Touch Press.

Categories
  • Actionscript (95)
  • AIR (16)
  • Flash (99)
  • Games (7)
  • Liberty (13)
  • Life (53)
  • Shaders (20)
  • Unity3D (21)
Recent Comments
  • MainDepth on Unity Ripple or Shock Wave Effect
  • Devon O. on Unity Ripple or Shock Wave Effect
  • Feral_Pug on Unity Ripple or Shock Wave Effect
  • bavvireal on Unity3D Endless Runner Part I – Curved Worlds
  • Danielius Vargonas on Custom Post Processing with the LWRP
Archives
  • December 2020 (1)
  • December 2019 (1)
  • September 2019 (1)
  • February 2019 (2)
  • December 2018 (1)
  • July 2018 (1)
  • June 2018 (1)
  • May 2018 (2)
  • January 2018 (1)
  • December 2017 (2)
  • October 2017 (1)
  • September 2017 (2)
  • January 2017 (1)
  • July 2016 (1)
  • December 2015 (2)
  • March 2015 (1)
  • September 2014 (1)
  • January 2014 (1)
  • August 2013 (1)
  • July 2013 (1)
  • May 2013 (1)
  • March 2013 (2)
  • December 2012 (1)
  • November 2012 (1)
  • September 2012 (3)
  • June 2012 (2)
  • May 2012 (1)
  • April 2012 (1)
  • December 2011 (2)
  • October 2011 (3)
  • September 2011 (1)
  • August 2011 (1)
  • July 2011 (1)
  • May 2011 (2)
  • April 2011 (2)
  • March 2011 (1)
  • February 2011 (1)
  • January 2011 (2)
  • December 2010 (3)
  • October 2010 (5)
  • September 2010 (1)
  • July 2010 (2)
  • May 2010 (5)
  • April 2010 (2)
  • March 2010 (7)
  • February 2010 (5)
  • January 2010 (5)
  • December 2009 (3)
  • November 2009 (1)
  • October 2009 (5)
  • September 2009 (5)
  • August 2009 (1)
  • July 2009 (1)
  • June 2009 (2)
  • May 2009 (6)
  • April 2009 (4)
  • March 2009 (2)
  • February 2009 (4)
  • January 2009 (1)
  • December 2008 (5)
  • November 2008 (2)
  • September 2008 (1)
  • August 2008 (6)
  • July 2008 (6)
  • June 2008 (9)
  • May 2008 (4)
  • April 2008 (3)
  • March 2008 (4)
  • February 2008 (9)
  • January 2008 (7)
  • December 2007 (6)
Copyright © 2021 Devon O. Wolfgang