Flash penetration stats for March 2009 now live, graphs updated

Adobe has updated the Flash version penetration statistics, showing Flash 10 with an average 74% penetration rate for March 2009.

This sounds fine – considering Flash Player 10 was released less than 6 months before – but when updating my graphics with a historic view, it’s clear the adoption rate has slowed down a bit. Previously, it was the player with the fastest adoption rate to date; now, it has a curve that brings it on par with how version 9.115 did (the second best adoption rate curve to date).

This is speculation on my part, but the relative slow down may probably be attributed to the lack of a killer application of Flash Player 10. If I remember correctly, developers and publishers had many reasons to adopt Flash 9 (AS3, AVM2 performance) and Flash 9.115 (h.264 and hardware-accelerated video playback) – that made several websites (like MySpace) require its installation, accelerating adoption considerably. Flash 10 had nothing of the sort – and, frankly, I don’t think I’ve seen any real work done for or requiring Flash 10. That’s not to say Flash 10 lacks features – hey, I love Vectors and the new 3D capabilities, and  I can’t wait until I’m able to use it in every project – but they’re mostly aimed at developers, and most of the new player features can be emulated in Flash 9 (even if it means lower performance), giving little reason for exclusive FP10 work right now.

Still, that it managed to hold such a quick adoption rate with no artificial stimulus is probably a testament to the overall acceptability of the plugin among users. Name recognition may be helping in making people update faster than they normally would because they know what to expect.

Changing the subject just a bit, other interesting ramification is that now we’re seeing the raise of automatic player version and stat tracking. Websites like RIA Stats and StatOwl also track plugin (and plugin version) penetration, and have lower penetration numbers for Flash 10 – 64% and 55%, respectively. Food for thought.

And I still wish Google would publish global stats from its Google Analytics service.

The obligatory post-Encontro de Web Design post

Note: this post is in Brazilian Portuguese. Its contents – in which I talk about a presentation I’ve given a couple of days ago – are only important for people who live in Brazil, and as such, I’m opening another exception and writing in my own language. Sorry, everybody else. If you want, there’s a translation here.

Voltei anteontem do 14º Encontro de Web Design (EWD), no Rio de Janeiro, e agora finalmente tenho tempo pra escrever um pouquinho sobre isso.

Sem ser muito redundante e repetindo só um pouco o que já foi dito por muitos dos participantes, foi um ótimo evento. Talvez algo possa ser reformulado, como colocar tempo para perguntas e respostas no final de cada palestra – evitando misturar muitos assuntos diferentes na mesa redonda final ou fragmentar a audiência – ou adicionar mais “tracks” simultâneos no futuro, mas, no geral, eu acho que o saldo foi bastante positivo. A Cristiane, a Adriana e todos os envolvidos merecem os parabéns pela organização.

14º Encontro de Webdesign - foto por Luís Ricardo

14º Encontro de Webdesign - foto por Luís Ricardo

Eu sou especialmente agradecido pela oportunidade de ter falado lá, ainda que acredite que o conteúdo da minha apresentação – que era mais focado em um aspecto do mercado de desenvolvimento – tenha sido menos um “convite para reflexão” do que as outras palestras, em especial a do Roberto Cassano (que realmente abriu meus olhos).

Agradeço também em especial ao Bruno Ribeiro e a toda sua família por terem me recebido super bem. Eles tiveram uma papel muito importante em fazer com que esta breve visita ao Rio tenha sido tão agradável como foi.

Agora ambos o EWD e o Encontro de TI fazem as malas e preparam-se para aportar na capital Paulista – no dia 25 de Abril, teremos os mesmos 14º EWD e 2º ETI em São Paulo. Eu vou estar lá dando a mesma palestra – ainda que um pouco reformulada, e falando mais devagar. :)

Esta também é a razão para ainda não disponibilizar o slideshow da minha apresentação ainda; ele estará no ar dia 25.

Até lá!

Talking tomorrow: Encontro de Webdesign

Like I mentioned earlier, tomorrow I’ll be at Rio de Janeiro at the 14th Encontro de Webdesign (“Webdesign Meeting”), giving a presentation whose title translates to something like “Rich interfaces as tools for public involvement”. It’s basically a talk that aims to show why and how rich interface platforms (Flash and others) can be used, with a few cases studies (in Flash).

Other presentations include talks by Roberto Cassano and Gil Giardelli. There’s also an IT meetup happening simultaneously so it should be interesting. I’ll probably be writing random, disjointed posts from there using my Brazilian Portuguese Twitter account. See you there!

Online applications: raster image editors

One of the topics I’ve delved the most into while creating my graduation project last year was web-based applications – “application-like” websites in which you can do tasks that were usually restricted to full-fledged applications you usually have to install on your own computer.

In my opinion, there’s this silent revolution going on, where we’re moving many (but not all) of the tasks we usually need to do on a computer to web-based applications. Researching – and, specially, actually using those applications – made me understand the whole thing a bit better. It’s not just about the Cloud or about social media or whatever Web 2.0 is supposed to be about, it’s also about the fact that web-based applications can be pretty helpful under certain situations – something I learned first-hand when I was almost forced to switch all my in-college text editing to Google Docs, after they uninstalled Open Office from the campus’ computers.

This is a bigger topic and this article about “The Netbook Effect’ on Wired can probably explain it better than I could.

Anyway, it turns out there’s some nifty applications out there. Since I have a list of similar apps I used on my graduation project presentation, and prompted by a question from a friend, I figured I’d post them here in the hopes such a list is useful for someone else. So here it is: a list or raster image (bitmap) editors that are web-based and can be ran from anywhere with no installation. Most of them are based on Flash.

Full-fledged, Photoshop-style image editors:

Simpler, yet very useful image editors:

Tools

Experimental stuff

Have I forgotten something?

Preparing the next talk… with a little help from my (online) friends

Note: this post is in Brazilian Portuguese. Its contents – in which I ask for suggestions about an upcoming presentation I’ll give – are only important for people who live in Brazil, and as such, I’m opening an exception and writing in my own language. Sorry, everybody else. If you want, there’s a translation here.

No próximo dia 28 de março, vou dar uma palestra no 14º Encontro de Webdesign, que acontece no Rio de Janeiro. O título da palestra é “Interfaces ricas como ferramenta de envolvimento do público” e vou falar sobre como interfaces “ricas” – Flash, hoje, mas não necessariamente, amanhã – são utilizadas, em especial pelo mercado publicitário, como parte de sua estratégia online através da geração de conteúdo pelo público. Vou falar sobre o lance todo do ponto de vista de um desenvolvedor, e mostrar alguns exemplos (meus e de terceiros) de como isso tudo acontece. É uma coisa meio sobre publicidade mesmo, uma visão da indústria pra indústria (nada sobre ativismo social ou coisa assim, só pra deixar claro). Não que eu seja um amante da publicidade, já que sou programador e vou falar mais da parte prática da coisa, mas enfim.

Bom, pegando carona neste post do Roberto Cassano, e até porque o evento está focado em redes sociais, queria perguntar pro público que pretende comparecer a este evento (ou, potencialmente, ao mesmo evento, em outras localidades) o que esperam da apresentação. Na verdade, já tenho a estrutura da apresentação planejada (introdução sobre a plataforma; contextualização e comparação com outras plataformas e utilização, problemas e vantagens; vários cases; detalhes técnicos como métricas), mas ainda existem tópicos que posso diminuir ou dar mais ênfase de modo a aproveitar melhor o tempo de apresentação (45 minutos) e até porque não vai ter rodada de perguntas imediatamente após a palestra (só mais tarde, numa mesa redonda).

Não vou fazer um form do Google Docs, mas queria perguntar o seguinte: tem algo específico que vocês querem ver explicado na palestra? Tem algum assunto, polêmico ou não, que vocês acham que precisa falar? Tem algo que precisa ser explicado? Vocês detestam Flash e precisam ver razão pra ele ser usado? Vocês adoram Flash e precisam ver razão pra ele não ser usado? (E quando falo “Flash”, eu me refiro também a plataformas de “interface rica” semelhantes – estou juntando Flash, SilverLight, JavaFX e etc no mesmo saco).

Pergunto isso pra todos, mas mais quem não trabalha especificamente na área de desenvolvimento Flash (ou semelhantes) mesmo. Imagino que o público da palestra seja um público mais misto, e às vezes a gente fica meio alienado quando falamos só com nossos pares, então fico curioso pra saber se tem algo que esqueci de colocar na minha estrutura.

Sei que as perguntas são bastante genéricas, mas enfim, fica aí o pedido. Respostas podem ser colocadas nos comentários do post, enviadas pro email zeh arroba zehfernando ponto com, enviadas via Twitter, etc etc. Comentários podem ser anônimos e críticos, mas tenho alergia a flames, então keep it beautiful. Valeu!

Changing a MovieClip’s registration point painlessly

And while I’m still in the subject, here’s a final example of how one can use getter/setters do add some functionality that doesn’t normally exist in a MovieClip: altering the registration point of a MovieClip.

This is some commonly requested functionality. There are several libraries out there that do the trick, I suppose, but a long time ago, during my first AS3 project, none of them worked the way I wanted to, so I had to build my own.

It works like this: the Class PointMovieClip – again, by lack of a better name – has two new properties, registrationX and registrationY. These define where the display object’s axis is located (inside its own coordinate space), and obviously, default to 0, 0. If you change them, it’s as if you changed the registration point.

// Moves the registration point of an object 10 pixels down and to the right from its original position
myPMC.registrationX = 10;
myPMC.registrationY = 10;

// Rotates the object from the new position
myPMC.rotation = 45;

The interesting thing about this example is that it works by overriding existing properties such as x and y, and adding some additional functionality to rotation, scaleX and scaleY. The getter/setters, in this case, are intercepting the user’s changes to those values and making it act accordingly, so other than adding registrationX and registrationY, it’s maintaining the same MovieClip API, but adding new functionality to it.

package com.zehfernando.display {
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.geom.Point;	

	/**
	 * @author Zeh Fernando
	 */
	public class PointMovieClip extends MovieClip {

		// Instance properties ----------------------------------------------------------------

		protected var _registrationX:Number;		// Registration point X
		protected var _registrationY:Number;		// Registration point Y
		protected var _x:Number;					// User-defined X
		protected var _y:Number;					// User-defined Y

		protected var setToUpdate:Boolean;			// Whether this instance is already set to update on the next Event.RENDER

		// ================================================================================================================
		// CONSTRUCTOR ----------------------------------------------------------------------------------------------------

		public function PointMovieClip() {
			super();

			// Reads the current __values to keep them
			_x = super.x;
			_y = super.y;
			_registrationX = 0;
			_registrationY = 0;
			fixPosition();
		}

		// ================================================================================================================
		// INTERNAL INSTANCE functions ------------------------------------------------------------------------------------

		protected function fixPosition(): void {
			// Using localToGlobal/globalToLocal is less precise than doing it mathematically, but the end result is more accurate inside Flash because it's in sync with Flash's positioning and rotating limitations
			var op:Point = new Point(0, 0);
			var rp:Point = new Point(_registrationX, _registrationY);
			rp = parent.globalToLocal(localToGlobal(rp));
			op = parent.globalToLocal(localToGlobal(op));
			super.x = _x - (rp.x - op.x);
			super.y = _y - (rp.y - op.y);
		}

		protected function requestPositionFix(): void {
			if (Boolean(stage) && !setToUpdate) {
				setToUpdate = true;
				stage.addEventListener(Event.RENDER, onRender, false, 0, true);
				stage.invalidate();
			}
		}

		// ================================================================================================================
		// EVENT functions ------------------------------------------------------------------------------------------------

		protected function onRender(e:Event): void {
			stage.removeEventListener(Event.RENDER, onRender);
			setToUpdate = false;
			fixPosition();
		}

		// ================================================================================================================
		// ACCESSOR functions ---------------------------------------------------------------------------------------------

		override public function get x(): Number {
			return _x;
		}
		override public function set x(__value:Number): void {
			_x = __value;
			requestPositionFix();
		}

		override public function get y(): Number {
			return _y;
		}
		override public function set y(__value:Number): void {
			_y = __value;
			requestPositionFix();
		}

		override public function set rotation(__value:Number): void {
			super.rotation = __value;
			requestPositionFix();
		}
		override public function set scaleX(__value:Number): void {
			super.scaleX = __value;
			requestPositionFix();
		}
		override public function set scaleY(__value:Number): void {
			super.scaleY = __value;
			requestPositionFix();
		}

		public function get registrationX(): Number {
			return _registrationX;
		}
		public function set registrationX(__value:Number): void {
			_registrationX = __value;
			requestPositionFix();
		}

		public function get registrationY(): Number {
			return _registrationY;
		}
		public function set registrationY(__value:Number): void {
			_registrationY = __value;
			requestPositionFix();
		}

	}
}

One last note: with this class, changing the registration point’s X and Y will move the object around, as it keeps the previous x and y positions instead of offsetting them to match; this is something I actually needed in my implementation as there were moments I tweened that value (together with x, y and rotation – basically, sliding, rotating rectangles on screen) and wanted the object to respond accordingly in a smooth fashion.

While there may be moments one needs to rotate a display object from a given point with the x and y changing immediately to match, I believe the above implementation to work better when animating things across screen.

Creating a MovieClip class for designers

Riding on what I wrote yesterday about using getter/setters for actual state control, here’s another example of how getter/setters can be used to control how your display assets work and make your life simpler.

For a while, for me, it was quite common to employ Tweener’s ColorShortcuts if I wanted to, say, tween the brightness or contrast of an image in Flash. However, there was a problem if I wanted to change the image attributes without animating it; while Tweener would let me do a transition in “0″ time (applying it immediately), it’s odd that I had to use a tweening engine to do something that wasn’t related to tweening at all. Additionally, since Tweener’s color shortcuts try to apply new properties to a DisplayObject without using new variables, it was common that a special tweening would overwrite a visual effect previously applied to the object, and this is hard to solve from an external class since you don’t have a very tight control of what happens with an object.

The correct solution is having a DisplayObject class that employs all the features you want and is completely independent of the tweening engine used. This meant that, for color shortcuts, you’d ideally have a sort of a MovieClip class with attributes like brightness, contrast, etc.

I’ve used variations of this on my work for a while, but today I finally sat down and wrote a more generic display class with properties that allow anyone to adjust some of its color properties. By lack of a better name, it’s called DesignerMovieClip, and it extends MovieClip. It works exactly like the class it extends, but adds a few new properties. Here’s a basic example (that doesn’t actually change the way the object works because it’s setting the properties to the default values):

var myDMC:DesignerMovieClip = new DesignerMovieClip();
addChild(myDMC);
(...)
myDMC.saturation = 1;     // Saturation: 0 (grayscale) -> 1 (normal, default) -> 2+ (highly saturated)
myDMC.contrast = 1;       // Contrast: 0 (grey) -> 1 (normal) -> 2 (high contrast)
myDMC.brightness = 0;     // Brightness offset: -1 (black) -> 0 (normal) -> 1 (full white)
myDMC.exposure = 1;       // Brightness multiplier: 0 (black) -> 1 (normal) -> 2 (super bright)
myDMC.hue = 0;            // Hue offset in degrees: -180 -> 0 (normal) -> 180

To super-saturate an image, you’d do this:

myDMC.saturation = 2;

And obviously, you can tween it with whichever tweening engine you use. In pseudo-code, it looks like this:

SomeTweenEngine.doTween(myDMC, {saturation:2, time:1});

Internally, this class works by adding a ColorMatrixFilter that do all the color changes to the filters list. You can still set the filters manually, however – it concatenates them all before setting the object’s filters. Nothing is overwritten, and you even still access the object’s transform.colorTransform’s properties. It’s as clean, and safe, of a solution as there can be.

An important disclaimer: this code is heavily based on Mario Klingemann’s Color Matrix class (the same code that’s used in Tweener’s color shortcuts, although the values the properties use are changed). I actually didn’t change much of his code, just stripped down to what I used, maybe changed the way some original values are treated, and then encapsulated in a self-contained display class.

The actual AS3 class is below. It’s simple and could use some improvement, but I guess it works for most cases. It also uses the stage.invalidate() “trick” to avoid re-applying the same thing every time a different display property changes.

package com.zehfernando.display {
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.filters.ColorMatrixFilter;	

	/**
	 * @author Zeh Fernando
	 */
	public class DesignerMovieClip extends MovieClip {

		// Sources:
		//
		// http://www.graficaobscura.com/matrix/index.html
		//
		// And specially Mario Klingemann's ColorMatrix class 2.1:
		// http://www.quasimondo.com/archives/000565.php
		// http://www.quasimondo.com/colormatrix/ColorMatrix.as
		// http://www.quasimondo.com
		// His code is licensed under MIT license:
		// http://www.opensource.org/licenses/mit-license.php

		// Static constants -------------------------------------------------------------------

		// Defines luminance using sRGB luminance
		protected static const LUMINANCE_R:Number = 0.212671;
		protected static const LUMINANCE_G:Number = 0.715160;
		protected static const LUMINANCE_B:Number = 0.072169;

		// Instance propertes -----------------------------------------------------------------

		protected var setToUpdate:Boolean;		// Whether this instance is already set to update on the next Event.RENDER

		// Color properties interface
		protected var _saturation:Number;		// Saturation: 0 (grayscale) -> 1 (normal, default) -> 2+ (highly saturated)
		protected var _contrast:Number;			// Contrast: 0 (grey) -> 1 (normal) -> 2 (high contrast)
		protected var _brightness:Number;		// Brightness offset: -1 (black) -> 0 (normal) -> 1 (full white)
		protected var _exposure:Number;			// Brightness multiplier: 0 (black) -> 1 (normal) -> 2 (super bright)
		protected var _hue:Number;				// Hue offset in degrees: -180 -> 0 (normal) -> 180 

		// Matrices
		protected var saturationMatrix:Array;
		protected var contrastMatrix:Array;
		protected var brightnessMatrix:Array;
		protected var exposureMatrix:Array;
		protected var hueMatrix:Array;

		// Overridden properties
		protected var _filters:Array;

		// ================================================================================================================
		// CONSTRUCTOR ----------------------------------------------------------------------------------------------------

		public function DesignerMovieClip() {
			super();
			setToUpdate = false;
			filters = [];
			saturation = 1;
			contrast = 1;
			brightness = 0;
			exposure = 1;
			hue = 0;
		}

		// ================================================================================================================
		// INTERNAL INSTANCE functions ------------------------------------------------------------------------------------

		protected function updateSaturationMatrix(): void {
			// Create the pre-calculated saturation matrix

			var nc:Number = 1-_saturation;
			var nr:Number = LUMINANCE_R * nc;
			var ng:Number = LUMINANCE_G * nc;
			var nb:Number = LUMINANCE_B * nc;

			saturationMatrix = [
				nr+_saturation,	ng,				nb,				0,	0,
				nr,				ng+_saturation,	nb,				0,	0,
				nr,				ng,				nb+_saturation,	0,	0,
				0,  			0, 				0,  			1,  0
			];

			requestVisualUpdate();
		}

		protected function updateContrastMatrix(): void {
			// Create the pre-calculated contrast matrix

			var co:Number = 128 * (1-_contrast);

			contrastMatrix = [
				_contrast,	0,	0, 	0, 	co,
				0,	_contrast,	0, 	0, 	co,
				0,	0,	_contrast, 	0, 	co,
				0,	0,	0, 	1, 	0
			];

			requestVisualUpdate();
		}

		protected function updateBrightnessMatrix(): void {
			// Create the pre-calculated brightness matrix

			var co:Number = 255 * _brightness;

			brightnessMatrix = [
				1,	0,	0, 	0, 	co,
				0,	1,	0, 	0, 	co,
				0,	0,	1, 	0, 	co,
				0,	0,	0, 	1, 	0
			];

			requestVisualUpdate();
		}

		protected function updateExposureMatrix(): void {
			// Create the pre-calculated exposture matrix

			exposureMatrix = [
				_exposure,	0,	0, 	0, 	0,
				0,	_exposure,	0, 	0, 	0,
				0,	0,	_exposure, 	0, 	0,
				0,	0,	0, 	1, 	0
			];

			requestVisualUpdate();
		}

		protected function updateHueMatrix(): void {
			// Create the pre-calculated hue matrix

			var hAngle:Number = _hue / 180 * Math.PI;
			var hCos:Number = Math.cos(hAngle);
			var hSin:Number = Math.sin(hAngle);

			hueMatrix = [
				((LUMINANCE_R + (hCos * (1 - LUMINANCE_R))) + (hSin * -(LUMINANCE_R))), ((LUMINANCE_G + (hCos * -(LUMINANCE_G))) + (hSin * -(LUMINANCE_G))), ((LUMINANCE_B + (hCos * -(LUMINANCE_B))) + (hSin * (1 - LUMINANCE_B))), 0, 0,
				((LUMINANCE_R + (hCos * -(LUMINANCE_R))) + (hSin * 0.143)), ((LUMINANCE_G + (hCos * (1 - LUMINANCE_G))) + (hSin * 0.14)), ((LUMINANCE_B + (hCos * -(LUMINANCE_B))) + (hSin * -0.283)), 0, 0,
				((LUMINANCE_R + (hCos * -(LUMINANCE_R))) + (hSin * -((1 - LUMINANCE_R)))), ((LUMINANCE_G + (hCos * -(LUMINANCE_G))) + (hSin * LUMINANCE_G)), ((LUMINANCE_B + (hCos * (1 - LUMINANCE_B))) + (hSin * LUMINANCE_B)), 0, 0,
				0, 0, 0, 1, 0
          	 	];

			requestVisualUpdate();
		}

		protected function requestVisualUpdate(): void {
			if (Boolean(stage) && !setToUpdate) {
				setToUpdate = true;
				stage.addEventListener(Event.RENDER, onRender, false, 0, true);
				stage.invalidate();
			}
		}

		protected function doVisualUpdate(): void {
		 	// Create empty maytix
		 	var mtx:Array = [
		 		1,0,0,0,0,
				0,1,0,0,0,
				0,0,1,0,0,
				0,0,0,1,0
			];
			var temp:Array = [];

		 	// Precalculate a single matrix from all matrices by multiplication
		 	// The order the final matrix is calculated can change the way it looks
		 	var matrices:Array = [saturationMatrix, contrastMatrix, brightnessMatrix, exposureMatrix, hueMatrix];

		 	var i:int, j:int, mat:Array;
			var x:int, y:int;

			for (j = 0; j < matrices.length; j++) {
				i = 0;
				mat = matrices[j];
				for (y = 0; y < 4; y++ ) {

					for (x = 0; x < 5; x++ ) {
						temp[ int( i + x) ] =  Number(mat[i  ])      * Number(mtx[x]) +
									   		   Number(mat[int(i+1)]) * Number(mtx[int(x +  5)]) +
									   		   Number(mat[int(i+2)]) * Number(mtx[int(x + 10)]) +
									   		   Number(mat[int(i+3)]) * Number(mtx[int(x + 15)]) +
									   		   (x == 4 ? Number(mat[int(i+4)]) : 0);
					}
					i+=5;
				}
				mtx = temp;
			}

			// Update object filters
			var newFilters:Array = [new ColorMatrixFilter(mtx)];
			super.filters = newFilters.concat(_filters);
		}

		// ================================================================================================================
		// EVENT functions ------------------------------------------------------------------------------------------------

		protected function onRender(e:Event): void {
			stage.removeEventListener(Event.RENDER, onRender);
			setToUpdate = false;

			doVisualUpdate();
		}

		// ================================================================================================================
		// ACCESSOR functions ---------------------------------------------------------------------------------------------

		public function get saturation(): Number {
			return _saturation;
		}
		public function set saturation(__value:Number): void {
			_saturation = __value;
			updateSaturationMatrix();
		}

		public function get contrast(): Number {
			return _contrast;
		}
		public function set contrast(__value:Number): void {
			_contrast = __value;
			updateContrastMatrix();
		}

		public function get brightness(): Number {
			return _brightness;
		}
		public function set brightness(__value:Number): void {
			_brightness = __value;
			updateBrightnessMatrix();
		}

		public function get exposure(): Number {
			return _exposure;
		}
		public function set exposure(__value:Number): void {
			_exposure = __value;
			updateExposureMatrix();
		}

		public function get hue(): Number {
			return _hue;
		}
		public function set hue(__value:Number): void {
			_hue = __value;
			updateHueMatrix();
		}

		override public function get filters(): Array {
			return _filters;
		}
		override public function set filters(__value:Array): void {
			_filters = __value;
			requestVisualUpdate();
		}
	}
}

It's sort of funny that once you start to add functionality to existing objects and to reuse them, making them simpler but more powerful, it starts to resemble the way we used to do stuff in AS1 with prototypes and such - only that now we can use actual types and things like autocompletion.

There are other variations of this kind of class I've used previously, but that's meant for future posts, I guess.

Using numeric values for state control

Something occurred to me one of these days. There’s something I’ve been doing for quite a while, but I’ve never discussed it with anybody else. I’m sure it all makes sense, somehow, or that there’s some better way to describe it – perhaps it has some fancy design pattern name – but for the sake of clarity and future linking, I decided to write about it. I also haven’t been talking about actual code for a while, so here it goes. It’s a big long-winded.

When creating custom objects with ActionScript, it’s pretty common to add some state variables to their classes. For example, suppose we have a FancyButton class, and we want to give developers the ability to disable or enable the button. Normally, we’d create the interface like this:

// Enables the button
myFancyButton.enabled = true;

// Disables the button
myFancyButton.enabled = false;

Then, inside the class, we’d just have a property, something like this:

class FancyButton extends Sprite {

	public var enabled:Boolean;

	function FancyButton() {
		enabled = true; // Enabled by default
	}

	(...other code...)

}

Then, when needed, the code inside the button would check for the value of enabled, and react accordingly – say, allowing the user to click it or not.

Of course, when we’re feeling fancy, we might as well transform it into a getter/setter property, and add functionality to when the property is changed. Like so:

class FancyButton extends Sprite {

	protected var _enabled:Boolean; // Actual value

	function FancyButton() {
		enabled = true; // Enabled by default
	}

	(...other code...)

	public function get enabled(): Boolean {
		return _enabled;
	}

	public function set enabled(__value:Boolean): void {
		_enabled = __value;
		alpha = _enabled ? 1 : 0.5;
	}

}

This allows the class to run whatever code we want once the value is changed – like maybe making the button semi-transparent when disabled, or fully visible otherwise (this is what the code above is doing). This is nothing fancy, basic ActionScript/OOP coding, but sets the context of my post.

Let me open another topic here first. I’ve always played a first-person shooter game called QuakeWorld, a multiplayer-only version of the classical game Quake. QuakeWorld is known for having many options you can change with the console, making the game pretty customizable, at least when compared to most first-person shooters. For example: when playing the game, you view your own weapon on screen, but if you want, you can make it invisible with the console command r_drawviewmodel 0 (so you get more screen space). Setting it to 1 will make it visible, as default. This value is a boolean, represented by a number.

Some years ago, I started using FuhQuake as my main QuakeWorld client (there are several different QuakeWorld clients). It turns out that in FuhQuake, many of the “boolean” console configuration variables (cvars) can be represented as numbers, instead of booleans. This means that, for r_drawviewmodel, 0 is still invisible, and 1 is still visible, but 0.5 means 50% opacity.

At the time, the idea struck me as pretty odd but quite ingenious – after all, I actually prefer to have my weapon on screen (so I could know which weapon was selected) but I also wanted to see what was beneath it, as the weapons tend to occupy some pretty large portion of the screen. As such, I use a r_drawviewmodel value of 0.3 on my QuakeWorld config file.

Almost without thinking, I adopted this same idea in most of the code I write. This means that, instead of my FancyButton have an enabled property which is a Boolean, it’s actually a Number that can go from 0 to 1 – 0 meaning disabled, 1 meaning enabled, and all values in between meaning whatever I want them to mean – say, disabled. The functionality, internally, looks the same.

class FancyButton extends Sprite {

	protected var _enabled:Number; // Actual value

	function FancyButton() {
		enabled = 1; // Enabled by default
	}

	(...other code...)

	public function get enabled(): Number {
		return _enabled;
	}

	public function set enabled(__value:Number): void {
		_enabled = __value;
		alpha = _enabled == 1 ? 1 : 0;
	}

}

What changes the most is when the Class code checks for whether the button’s enabled or not – and, of course, references to the enabled property of the instance would be slightly different, like so:

// Enables the button
myFancyButton.enabled = 1;

// Disables the button
myFancyButton.enabled = 0;

Well, why bother with this change then? It turns out that when I need to work with Flash, it’s pretty common that I have to smoothly change the state of an object – like enabling and disabling a button. With a numeric property, I can make the state value be the transition, and then have more control over a button state – either changing it with an animation, or changing it immediately when needed. For example, to make sure the enabled property changes the visible state of my button smoothly, the correct class’ property’s set function would be something like this:

class FancyButton extends Sprite {

	(...)

	public function set enabled(__value:Number): void {
		_enabled = __value;
		// Alpha goes from 0.5 to 1 as _enabled goes from 0 to 1
		alpha = 0.5 + _enabled * 0.5;
	}

}

(This is not something that would be used every time, of course. In many cases, having have a hard, Boolean property is fine, then you can do the animation transition inside the set function as necessary, and actually avoid the Class user’s the hassle of tweening anything. But this is an specific case that applies to the enabled state of a button – which is just a simpler example I used to illustrate my point – so please bear with me while I continue).

As it turns out, there are a number of advantages in using numbers to control the state of an object, instead of using Booleans.

Take, for instance, the rollover state of a button. Consider a simple, semi-transparent button, that becomes fully visible during rollover. It’s quite common that such functionality will look like this:

class FancyButton extends Sprite {

	function FancyButton() {
		addEventListener(MouseEvent.ROLL_OVER, onRollOver);
		addEventListener(MouseEvent.ROLL_OUT, onRollOut);
		alpha = 0.5;
	}

	public function onRollOver(e:MouseEvent): void {
		alpha = 1;
	}

	public function onRollOut(e:MouseEvent): void {
		alpha = 0.5;
	}

}

Or, of course, you can use some tween for that, so it’ll have a nifty animation when rolled over (some pseudo-code):

import com.somepackage.SomeTweenEngine;

class FancyButton extends Sprite {

	function FancyButton() {
		addEventListener(MouseEvent.ROLL_OVER, onRollOver);
		addEventListener(MouseEvent.ROLL_OUT, onRollOut);
		alpha = 0.5;
	}

	public function onRollOver(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {alpha:1, time:0.4});
	}

	public function onRollOut(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {alpha:0.5, time:0.4});
	}

}

All fine and dandy. Suppose, however, you want to add more features to your button. Say, for instance, your non-focused button will be a bit blurred, and have a little glow when rolled over. It could look like this:

import com.somepackage.SomeTweenEngine;

class FancyButton extends Sprite {

	function FancyButton() {
		addEventListener(MouseEvent.ROLL_OVER, onRollOver);
		addEventListener(MouseEvent.ROLL_OUT, onRollOut);
		alpha = 0.5;
	}

	public function onRollOver(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {alpha:1, time:0.4});
		SomeTweenEngine.doTween(this, {glow:3, color:0xff0000, time:0.4});
		SomeTweenEngine.doTween(this, {blur:0, time:0.4});
	}

	public function onRollOut(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {alpha:0.5, time:0.4});
		SomeTweenEngine.doTween(this, {glow:0, color:0xff0000, time:0.4});
		SomeTweenEngine.doTween(this, {blur:4, time:0.4});
	}

}

That is, considering your tweening engine already supports “shortcuts” for filter tweening, and that they’re initialized (if needed).

Still, this code poses a problem. How do you set the initial state of the Button as unfocused? You’d either need to duplicate the tweenings functionality, call onRollOut (it would animate the object to the desired state however), or create a function that moves the object between states with a customizable time. This is something I’ve been doing previously, and it looks like so:

import com.somepackage.SomeTweenEngine;

class FancyButton extends Sprite {

	function FancyButton() {
		addEventListener(MouseEvent.ROLL_OVER, onRollOver);
		addEventListener(MouseEvent.ROLL_OUT, onRollOut);
		setStateNormal();
	}

	public function get onRollOver(e:MouseEvent): void {
		setStateFocused(0.4);
	}

	public function set onRollOut(e:MouseEvent): void {
		setStateNormal(0.4);
	}

	protected function setStateNormal(__time:Number = 0): void {
		SomeTweenEngine.doTween(this, {alpha:0.5, time:__time});
		SomeTweenEngine.doTween(this, {glow:0, color:0xff0000, time:__time});
		SomeTweenEngine.doTween(this, {blur:4, time:__time});
	}

	protected function setStateFocused(__time:Number = 0): void {
		SomeTweenEngine.doTween(this, {alpha:1, time:__time});
		SomeTweenEngine.doTween(this, {glow:3, color:0xff0000, time:__time});
		SomeTweenEngine.doTween(this, {blur:0, time:__time});
	}
}

This works great. However, there are two questions still raised – what if I want to control my state from outside, and what if I want to do something that isn’t normally supported by the tweening engine? The former would require all my external code to “know” what properties are changed, or for the setState* methods to be public; the latter would get me stuck.

Enter state variables. With state variables, you can control the tween the actual state the button is, and then just apply the state to the object. The above class would work like so:

class FancyButton extends Sprite {

	protected var _mouseFocused:Number; // Actual value

	function FancyButton() {
		addEventListener(MouseEvent.ROLL_OVER, onRollOver);
		addEventListener(MouseEvent.ROLL_OUT, onRollOut);
		mouseFocused = 0; // Normal by default
	}

	public function onRollOver(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {mouseFocused:1, time:0.4});
	}

	public function onRollOut(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {mouseFocused:0, time:0.4});
	}

	// Getter/setters

	public function get mouseFocused(): Number {
		return _mouseFocused;
	}

	public function set mouseFocused(__value:Number): void {
		_mouseFocused = __value;
		// Applies the focus value
		alpha = 0.5 + _mouseFocused* 0.5;
		filters = [
			new BlurFilter((1-_mouseFocused) * 4, (1-_mouseFocused) * 4),
			new GlowFilter(0xff0000, 1, _mouseFocused * 3, _mouseFocused * 3)
		];
	}

}

“But Zeh”, I can hear people say, “this looks a lot more complicated. Why would I even want to use this crap?”

If you just said or thought so, then you’re right that it looks more complicated. However, I personally like to think that this approach is the cleanest in the sense that it allows me to set the state of an object to be whatever I want it to be, from the class itself or from outside of it, without having to deal with the actual property values; I don’t need the tweening class to actually support anything other than basic tweening, or to learn a new “shortcut” API in addition to standard DisplayObject features like filters, avoiding redundancy; and additionally, one of the most important aspects of this approach is that you can stack state properties and make the object react accordingly. Suppose, for example, that our FancyButton can also be disabled in addition to being focused; this would cut its opacity in half. Doing this with normal alpha tweening would be a big problem, because you’d need to check all the Boolean states of an object before determining what the target value should be. With numeric states, this would look like so:

class FancyButton extends Sprite {

	protected var _mouseFocused:Number;
	protected var _enabled:Number;

	function FancyButton() {
		addEventListener(MouseEvent.ROLL_OVER, onRollOver);
		addEventListener(MouseEvent.ROLL_OUT, onRollOut);
		mouseFocused = 0;
		enabled = 1;
	}

	// State redrawing

	public function redrawState(): void {
		// Applies the focus value
		alpha = ((0.5 + _mouseFocused * 0.5) + (0.5 + _enabled * 0.5))/2;
		filters = [
			new BlurFilter((1-_mouseFocused) * 4, (1-_mouseFocused) * 4),
			new GlowFilter(0xff0000, 1, _mouseFocused * 3, _mouseFocused * 3)
		];
	}

	// Events

	public function onRollOver(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {mouseFocused:1, time:0.4});
	}

	public function onRollOut(e:MouseEvent): void {
		SomeTweenEngine.doTween(this, {mouseFocused:0, time:0.4});
	}

	// Getter/setters

	public function get mouseFocused(): Number {
		return _mouseFocused;
	}

	public function set mouseFocused(__value:Number): void {
		_mouseFocused = __value;
		redrawState();
	}

	public function get enabled(): Number {
		return _enabled;
	}

	public function set enabled(__value:Number): void {
		_enabled = __value;
		redrawState();
	}

}

In the above code, the alpha of a fully focused and enabled button would be 1; a focused but not enabled button, as well as an enabled but not focused button, would have an alpha of 0.75; and a button that’s neither enabled nor focused would have an alpha of 0.5. That’s because they’re stacking – if I was simply changing the values themselves depending on the change of a property, I’d risk overwriting one animation with another, or ending up with the wrong value.

This may not sound like much, because, again, the focused/enabled button is a simple example. But if you take the idea and apply it to some of the most common visible objects you have to create in Flash, I believe you’ll find it quite useful. Or, well, at least I do.

Here’s another example that may illustrate why state control is better than direct property control. Suppose you have a box that you want to go from the left side of the screen to the right side of the screen in 3 seconds. Something like this:

myBox.x =  0;
SomeTweenEngine.doTween(myBox, {x:stage.stageWidth, time:0.6});

This will work. However, suppose the screen is resized during the animation, and you’re using a stage scaleMode of NO_SCALE (variable width). What to do?

Most people will say the normal solution is to interrupt the tween, setting a new goal. Or, maybe, if your tweening solution allows tweening references, you could just save the reference and change the target value. Something like this, in pseudo-code:

myBox.x =  0;
myTween = SomeTweenEngine.doTween(myBox, {x:stage.stageWidth, time:0.6});
stage.addEventListener(Event.RESIZE, onResizeScreen);

public function onResizeScreen(e:Event): void {
	if (Boolean(myTween) && myTween.isActive) {
		myTween.x = stage.stageWidth;
	}
}

This may work, but creating an exception to that opens up a big can of worms – every kind of animation that depends on a value that can change depending on the screen size will need a similar event. And that’s even considering you can save tweening references and change them later. For engines that don’t allow that – my own Tweener, for example, doesn’t unless yo hack its code – actually stopping and recreating tweenings is a much worse solution.

This (nice) animation is a good real-world example of that problem. It employs no resize detection during tweening – if you click to go to the next or previous slide, and resize your browser during the tweening, the final state won’t make a lot of sense – the slide will have the wrong position and scale, instead of being fully centered.

In cases like this, a solution would be to add an state property to the object – in the previous box example, an alignment property would probably make some sense, if you consider -1 to be full left alignment, and 1, full right alignment. The interface could work like this:

myBox.alignment = -1;
SomeTweenEngine.doTween(myBox, {alignment:1, time:0.6});

Then the code for myBox – which would render the x property useless, unless you extend and overwrite it to have some additional functionality – would look like this:

class MyFancyBox extends Sprite {

	protected var _alignment:Number = 0; // Default is centered

	(...class code...)
	// Getter/setters

	public function get alignment(): Number {
		return _alignment;
	}
	public function set alignment(__value:Number): Void {
		_alignment = __value;
		x = ((_alignment + 1)/2) * stage.stageWidth;
	}

}

Obviously, that’s some pseudo-code, with just the basic idea – to move the object to a new position but always based on the stage width. A final class could be properly constructed to, say, take the object’s width in consideration, allow x to work as an offset value (in addition to alignment), etc. The basic point, however, is that by adding a state property via a getter/setter, you don’t have to worry about exceptional behavior – like a window resize – anymore. Instead, you just take them into consideration when applying the state to the object.

And while I do use the focus/enabled functionality quite often, here’s a real, more useful example. I was creating an animation that should contain some text. This text must come into view with a fancy vertical blur effect (like a motion blur), and go away in the same way. I could have done it like this:

// Show
SomeTweenEngine.doTween(myText, {blurX:4, time:1});
SomeTweenEngine.doTween(myText, {alpha:1, time:1, onStart:function() { this.visible = true; }});

// Hide
SomeTweenEngine.doTween(myText, {blurX:0, time:1});
SomeTweenEngine.doTween(myText, {alpha:0, time:1, onComplete:function() { this.visible = false; }});

(And, of course, I could also employ some autoAlpha functionality, if the engine supported it, to automatically make it invisible)

Sure, it looks and works fine, but what if I want to use that on several different places, and what if I want to change the amount of blur it’s applied later? I need to hunt down everywhere I have the tweening start and change the code, or create a function to show and hide this object.

The solution I’ve chosen, instead, is to have a visibility property that applies directly to how I want my object to show and hide every time. Its interface works like so:

// Show
SomeTweenEngine.doTween(myText, {visibility:1, time:1});

// Hide
SomeTweenEngine.doTween(myText, {visibility:0, time:1});

And then, inside the code, of course, I have the appropriate getter/setter code, and state update function:

(...class code...)

// State redrawing

private function redraw(): Void {
	if (visibility > 0) {
		_alpha = _visibility;
		_visible = true;
		filters = _visibility == 1 ? [] : [new BlurFilter((1-_visibility) * 64, 1-_visibility, 2)];
	} else {
		_visible = false;
		filters = [];
	}
}

// Getter/setters

public function get visibility(): Number {
	return _visibility;
}

public function set visibility(__value:Number): Void {
	if (_visibility != __value) {
		_visibility = __value;
		redraw();
	}
}

(...class code...)

This is actual code used on some recent work I’ve done. And again, this might looks like more code, but I like to believe it’s actually less – you only write the functionality once, inside your class, then reuse when needed. You can then work on the object’s state whenever you please, and not worry about tweening support.

This may sound sort of crazy since I’ve gone out of my way to add a lot of (optional) shortcuts to Tweener. But the truth is, I haven’t been using those for a long, long time. While they may make your life easier when you need some quick functionality – say, autoAlpha and such – trying to use a tweening extension to control way too many features (specially features that are not directly available as a direct property) is a recipe for disaster. Nowadays, I like having a cleaner, tweening-independent solution, and honestly it has been working very well for even the most complex cases.

Finally, the above alternative is not a silver bullet, as it adds a few problems by itself – on the previous FancyButton class example, trying to tween both enabled and mouseFocused at the same time would cause redrawState() to be called twice per frame (see this for an explanation on the solution). But still, I think the advantages far outweight the disadvantages.

Creating a high-resolution poster with Processing

Last year I finally delved head-first into the wonderful world of Processing. It was one of those (many) times I could college as an excuse that allowed me to spend some more serious time with something that wasn’t directly related to what I do on my day-to-day work. I used the time to create some small experiments to learn the platform, and to help some colleagues with their Processing-based graduation projects – that is, never creating something final, or by myself, other than random experiments.

That’s why when the São Paulo-based band Omega Code started their open poster contest I knew that, instead of using normal illustration editors, I wanted create an entry using Processing. Additionally, my previous experiments were all based in video or real-time functionality, so creating a poster – static, high-res – would be great for a change.

The first idea that popped in my mind when I thought about what I wanted to build was that I didn’t want to use any kind of external asset; so no image composition or anything, I’d do it all with typography.

I did have to use one image, however. I created a black&white version of their template document, which contains the band logo, to serve as a guide of sorts for my poster.

Omega Code poster template

Omega Code poster template

Basically, this logo is used as a map for where I want to have different colors.

The second idea was what to use. Now, I’m an atheist, but I know from Xenogears Fallout 3 that the whole “Omega” thing comes from The Book of Revelations, and I figured the text of that chapter of The New Testament would fit the poster (and the overall concept of the contest) well.

I went to look for the Biblical text and, thankfully, there’s no shortage of Bible-based content on the web. More precisely, I found this website which contains the full text of all chapters from the Christian Bible, including the one I wanted, the Book of Revelations. And what’s best – in its original language.

The one I wanted was written in Greek, however. That poses a problem, since most fonts – including general use fonts like Arial – do not include the glyphs needed for proper Greek rendering. So it was with a big surprise that I found Gentium, a font made specially for Greek rendering – and with a free license to boot – that I could use for the poster. It looks beautiful, too.

With the ingredients ready, I went on to create the poster by writing Processing code.

As strange as this sounds, the most difficult part was actually getting the text rendering to work.

I created a text file containing the entire Book of Revelations, and created a quick sketch that could read random words from it and render those to the sketch area. The problem wasn’t in reading this text file, or getting UTF-8 based strings to read and write properly. The real problem was with getting them to render correctly at the sizes I wanted. This is because processing renders text as images, as is the norm with platforms that are meant for realtime graphics. That is to say, you have to generate raster image “tables” from true type files, posing a problem with quality: too big of a text, and it’d be blurred; too small, and it’d look awful.

Of course, I could generate different font files, one of each size of the funt, but since I wanted to use all kinds of text from size 5 to 300, this wasn’t entirely feasible.

The first thing I tried was to find some Processing library that used text as vector data – meaning it could work like, say, Flash, where you can scale text to your heart’s content without worries about quality. This proved a big problem, however, as the two such libraries I tested had problems of their own – incompatibilities with the Processing version I was using, I suppose.

In the end, I gave up on trying to use different libraries and went back to Processing’s original font support. I ended up doing something absolutely awful – regenerating the font table to memory every time the font size changes. Since this was all meant for a high resolution, non-realtime poster, it served its purpose well, but it was really slow. I started caching the fonts for each size after a while (at the expense of a lot of memory) and restricted the available font sizes to 50 variants, and this made things faster, but still this wouldn’t be possible for realtime text rendering.

With all set on the text rendering features, I went on to creating the actual poster. The first thing I did was write the start of the chapter on the background, as some simple, running text. This was meant to give some texture to the poster’s background.

Then I made the sketch read random points from the “template” map (the one in black and white). If the result was a black point, it’d paint a random word on that same position on the final image. The result was as such:

poster_done_1

This worked, but it wasn’t really what I wanted yet. I wanted something a bit more random, to give it more texture, even if always type-based. I made it randomize the size of the text as well too, and made it so that if the source background was white, the stamped text would be a very transparent black instead of simply ignoring that point. This was the result:

poster_done_3

Still not quite what I wanted, I made the algorithm check the template image to find the brightest color from the entire square that the new word would occupy (instead of just the center point). Now, I’m the first to admit this was done in a very dumb way – it runs the entire perimeter of the text bounding box, checking for the color of each pixel – but it served its purpose well, and heck, this was for a non-realtime sketch, I could afford to be optimization-challenged.

After implementing the box color checking feature, this was the result:

poster_done_6

After solving a few problems that would get the random font sizes to get stuck in the same size forever, I decided to add some more features to the background. For a first pass, instead of being fully white, the further from the band symbol’s center the new word was, the darker it would become – this would give the impression of a white glow around the band’s symbol. After running the sketch for a long time – it added a few words every frame – this was the result:

poster_done_9

Despite having way too much solid gray, that was almost the result I wanted. Next, I added some better pattern to the background, by making the text color actually vary depending on its angle from the symbol’s center, creating the impression of rays coming out of the symbol. This was the result, still in grayscale:

poster_done_11

Finally I added some color to it. I didn’t really want to make it too colorful, and after testing with the above image in Photoshop for a while, I came up with a combination that gave it the impression I wanted, of some sort of thing that’s coming out of an old book or printed on an old paper.

poster_done_15

The above image also shows a slightly different color detetion algorithm, as I made the text color detection a bit erratic (by using a smaller color selection rectangle). This was meant to make the logo look tighter, even at the expense of the precision of its forms. This is subtle, but I think it looks a lot better.

The final step was generating the image to be used. This image was supposed to be pretty big; thankfully, I build the sketch in way that it’s based on a global scale variable, so while the tests above were ran on a smaller version, I could simply change the scale and let it run to create the final image.

Like I said, the sketch generates the final poster by adding new words to it on every frame. The sketch adds 5 new words on every frame rendered, and runs the sketch for 20,000 frames (because I found the ideal result with 100,000 words randomly placed). But since it’s manipulating a image with dimensions of 2953 x 4185 pixels, it’s a rather slow process – the final image took almost 3 hours to be generated (see this video to understand how it works).

And heck, there’s even a Twitter log with more test images if you want to see them, as I was posting to it while I was working on the final poster.

The final result is pretty simple, visually speaking, but I think it solves the concept well. And while it uses an image as its base, it’s still entirely based around typography, as even the background patterns are created by adding a lot of text with low opacity, so I think it responds well to this self-imposed restriction too.

For more information about the poster, see all fan-made entries to Omega Code’s poster contest, including the above one. The contest goes until March 31, and everybody can send their entries. You can also see the original posters, made by several renowned designers.

This entire post was made because I wanted to explain what the poster contains, and specially because I wanted to make the Processing source code available: download it here. It includes all assets used (font file, image map, and source text file). You’ll obviously need Processing to run it.

Caveat: the above is exactly what I used, and I did try a lot of different things during the development process, so it’s a very non-optimized, non-cleaned up code. There’s a lot of strange things there, like old lines and functions that are commented out, some rather confusing equations, it only uses one class, and all that kind of stuff that a coder does when he’s writing for himself. But it works: press space to hide/show the final result, or S to save the image. It also saves the image automatically every 1,000 frames (or 5,000 words). And feel free to make new entries to Omega Code’s contest based on it if you so want, or of course, create entirely new submissions.

The secrets of the universe lie between 0 and 1

Interesting link for people interested in interpolation and tweening, with Flash/ActionScript or otherwise: Interpolation Tricks by Jari Komppa. An award-winning Demo coder, he explains concepts related to programmatic animation from a different perspective – he never mentions Robert Penner’s easing equations, but at the same time he’s talking about the same thing, even if using different equations. And, of course, it’s nice to find someone explain the beauty of the 0..1 range so didactically, so I think it’s some great reading.