Browse the notebook

Tag: as3

base32 Twitter Coordinates

[SWF(width = 800, height=700, frameRate=30, backgroundColor=0x000000)]
var canvas:BitmapData = new BitmapData(1000,800,false, 0x000000);
addChild(new Bitmap(canvas));

var coords:String ="";
var index:int = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
 
var s:Shape = new Shape();
with (s.graphics) beginFill(0xFFFFFF, 0.3), drawCircle(4,4,4)
var brush:BitmapData = new BitmapData(10,10, true, 0x00000000);
brush.draw(s);

var pnt:Point = new Point();
function onLoop(evt:Event):void {
     if (coords.length > 0){
		 for (var i:int = 0; i< 100;i++){
			 if (index < coords.length){
				 pnt.x+= 0.2;
				 pnt.y = parseInt(coords.substr(index,3), 32) / 2;
				 index+=3;
				 canvas.copyPixels(brush, brush.rect, pnt, null, null, true);
			 }else{
				break;
				removeEventListener(Event.ENTER_FRAME, onLoop);
			 }
		 }
	 }
}

var loader:URLLoader = new URLLoader();
var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
var vars:URLVariables = new URLVariables();
vars.q = "as3, flash";
vars.rpp = "100";
vars.page = 1;
vars.lang = "en";
req.data = vars;
req.method = URLRequestMethod.POST;
loader.load(req);
loader.addEventListener(Event.COMPLETE, onLoaded);
function onLoaded(evt:Event):void{
	var searchData:XML = new XML(loader.data);
	var atom:Namespace = searchData.namespace("");
	default xml namespace = atom;
	var titles:String = "";
	for each(var entry:XML in searchData.entry){
		titles += entry.title.toString();
	}
	var index:int = 0;
	var words:Array = titles.split(" ");
	words.sort();
	for (var i:int = 0; i<words.length; i++){
		if (words[i].match(/RT|@|#|http/g).length == 0){
			var word:String = words[i].replace(/[W]/g, "");
			if (word.length > 1){
				coords += word + " ";
			}
		}
	}
}

This snippet does a twitter search and sorts the results alphabetically. It then reads through the results 3 characters at a time – each set of 3 characters is converted to base32 and then used a y coordinate on a plot.

In order for the swf to be worth looking at, I think I’d need to add an input field. I may do that later… but for now here are a few stills:

Read snippet: base32 Twitter Coordinates

Twitter Texture Alphabet

[SWF(width = 1000, height=800, frameRate=60)]

// if you don't have flex you'll need to embed this font in your library
[Embed(source="/Library/Fonts/Verdana.ttf", fontFamily="Verdana")]
var Verdana:Class;

var canvas:BitmapData = new BitmapData(1000,800,false, 0xFFFFFF);
addChild(new Bitmap(canvas));
var overlay:BitmapData = new BitmapData(1000,800,true, 0x01FFFFFF);
 

var txt:TextField = TextField(addChild(new TextField()));
with (txt){
	defaultTextFormat = new TextFormat("Verdana", 10);
	embedFonts = true;
	width = stage.stageWidth-20;
	height = stage.stageHeight-20;
	multiline = true;
	wordWrap = true;
	text ="";
	textColor = 0x444444;
	selectable = false;
	x = y = 10;
	text = "loading...";
}


var selectWords:Array = [];
var currFirstLetter:String="";
var prevFirstLetter:String="";
var index:int = 0;
var anchorX:Number = 0, anchorY:Number = 0, theta:Number, radius:Number;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	 canvas.copyPixels(overlay, overlay.rect, new Point(0,0), null, null, true);
	 var leng:int = selectWords.length;
     if (leng > 0){
		 var word:String = selectWords[index % leng];
		 trace(word);
		 currFirstLetter = word.charAt(0);
		 if (currFirstLetter != prevFirstLetter){
			 anchorX = Math.random() * (stage.stageWidth - 200) + 100
			 anchorY = Math.random() * (stage.stageHeight - 200) + 100;
			 theta = Math.random() * Math.PI * 2;
			 radius = 50 + Math.random() * 100;
			 txt.textColor = [0,0xFFFFFF,0xCCCCCC,0x666666][int(Math.random()*4)];
		 }else{
			 txt.x = anchorX + radius * Math.cos(theta);
			 txt.y = anchorY + radius * Math.sin(theta);
			 theta += Math.random() * .1;
			 radius += 3;
			 txt.scaleX = txt.scaleY = 1 + Math.random();
			 if (int(Math.random()*30) == 1) txt.scaleX = txt.scaleY = 1 + Math.random()*10;
			 txt.rotation = theta / Math.PI * 180;
			 txt.text = word;
			 canvas.draw(txt, txt.transform.matrix);
		 }
		 prevFirstLetter = currFirstLetter;
		 index++;
	 }
}

var loader:URLLoader = new URLLoader();
var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
var vars:URLVariables = new URLVariables();
vars.q = "alphabet";
// results per page
vars.rpp = "100";
vars.page = 1;
vars.lang = "en";

req.data = vars;
req.method = URLRequestMethod.POST;
loader.load(req);
loader.addEventListener(Event.COMPLETE, onLoaded);									
function onLoaded(evt:Event):void{
	var searchData:XML = new XML(loader.data);
	var atom:Namespace = searchData.namespace("");
	default xml namespace = atom;
	var titles:String = "";
	for each(var entry:XML in searchData.entry){
		titles += entry.title.toString();
	}
	var index:int = 0;
	var words:Array = titles.split(" ");
	for (var i:int = 0; i<words.length; i++){
		// exclude a few things
		if (words[i].match(/RT|@|#|http/g).length == 0){
			selectWords[index++] = words[i].replace(/s|r|n|"/g, "");
		}
	}
	selectWords.sort();
	txt.text =""
        removeChild(txt);
}

This snippet draws a texture using a twitter search for the word “alphabet”. The results are arranged alphabetically and used to draw a texture.


Have a look at the swf:

Read snippet: Twitter Texture Alphabet

I want Twitter

[SWF(width = 800, height=600, frameRate=15)]

var littleTxt:TextField = TextField(addChild(new TextField()));
with (littleTxt){
	defaultTextFormat = new TextFormat("_sans", 10);
	width = stage.stageWidth-20;
	height = stage.stageHeight-20;
	multiline = true;
	wordWrap = true;
	text ="";
	textColor = 0x444444;
	selectable = false;
	x = y = 10;
}

var txt:TextField = TextField(addChild(new TextField()));
with (txt){
	defaultTextFormat = new TextFormat("_sans", 90);
	autoSize = "center";
	x = 0
	y = stage.stageHeight / 2 - 61
	width = stage.stageWidth;
	selectable = false;
	text = "loading";
}

var selectWords:Array = [];
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
     if (selectWords.length > 0){
		var word:String = selectWords[int(Math.random() * selectWords.length)];
		txt.text = word;
		littleTxt.appendText(word+" ");
	 }
}

var loader:URLLoader = new URLLoader();
var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
var vars:URLVariables = new URLVariables();
vars.q = "i want";
// results per page
vars.rpp = "50";
vars.page = 1;
vars.lang = "en";

req.data = vars;
req.method = URLRequestMethod.POST;
loader.load(req);
loader.addEventListener(Event.COMPLETE, onLoaded);									
function onLoaded(evt:Event):void{
	var searchData:XML = new XML(loader.data);
	var atom:Namespace = searchData.namespace("");
	default xml namespace = atom;
	var titles:String = "";
	for each(var entry:XML in searchData.entry){
		titles += entry.title.toString();
	}
	var index:int = 0;
	var words:Array = titles.split(" ");
	for (var i:int = 0; i<words.length; i++){
		// exclude a few things
		if (words[i].match(/RT|@|#|http/g).length == 0){
			selectWords[index++] = words[i];
		}
	}
}

This snippet searches twitter for the phrase “I want” and then displays the results randomly word by word in a somewhat hypnotic way.


Have a look at the swf…

Read snippet: I want Twitter

I’m Twitter Search

[SWF(width = 400, height=600, frameRate=12)]
var loader:URLLoader = new URLLoader();
var req:URLRequest = new URLRequest("http://search.twitter.com/search.atom");
var vars:URLVariables = new URLVariables();
vars.q = "I'm";
// results per page
vars.rpp = "7";
vars.page = 1;

req.data = vars;
req.method = URLRequestMethod.GET;

loader.addEventListener(Event.COMPLETE, onLoaded);
loader.load(req);

// check for updates every 30 seconds - 
var timer:Timer = new Timer(30000);
timer.addEventListener(TimerEvent.TIMER, onTick);
timer.start();
function onTick(evt:TimerEvent):void{
	txt.htmlText = "loading...";
	loader.load(req);
}

var txt:TextField = TextField(addChild(new TextField()));
txt.defaultTextFormat = new TextFormat("_sans", 12);
with (txt){ x=10, y=10, width=stage.stageWidth-10;
height=stage.stageHeight, multiline = true, wordWrap = true; }
txt.htmlText = "loading...";
													
function onLoaded(evt:Event):void{
	var searchData:XML = new XML(loader.data);
	var atom:Namespace = searchData.namespace("");
	default xml namespace = atom;
	var htmlText:String = "<b>Last " + vars.rpp + " '" + vars.q + "' tweets:</b><br /><br />";
	for each(var entry:XML in searchData.entry){
		htmlText += entry.author.name.toString() + ": <br />";
		htmlText += entry.title.toString() + "<br /><br />";
	}
	txt.htmlText = htmlText; 
}

Was curious about the twitter search api so spent a few minutes and whipped up a quick demo – the api is simple and easy to understand…

As a test I created something that shows the last 7 tweets including the phrase I’m. A new search is done every 30 seconds… I chose the phrase I’m so that there will be different results every time a new search is done…

(more…)

Read snippet: I’m Twitter Search

Perlin Outlines

[SWF(width = 600, height=600, backgroundColor=0xCCCCCC, frameRate=24)]
var canvas:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight, false, 0x000000);
var blur:BitmapData = new BitmapData(stage.stageWidth,stage.stageHeight, false, 0x000000);
addChild(new Bitmap(canvas, "auto", true));

var w:int = canvas.width 
var hw:int = w / 2;
var size:int = w * w;
var seed:Number = Math.random()*100;
var pnt:Point = new Point();
var dy:Number = 0, dx:Number = 0;
var blr:BlurFilter = new BlurFilter(10,10,1);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	canvas.lock();
	canvas.perlinNoise(hw,hw,2,seed,false, false, 1, true, [new Point(dx, dy), new Point(-dx, -dy)]);
	var pix:Vector.<uint> = canvas.getVector(canvas.rect);
	for (var i:int = 0; i<size; i++){
		var col:uint = 255 - pix[i] << 4 & 0x00FF00;
		pix[i] = col << 8 | col | col >> 8;
	}
	canvas.setVector(canvas.rect, pix);
	blur.copyPixels(canvas, canvas.rect, pnt);
	blur.applyFilter(blur, blur.rect, pnt, blr);
	canvas.draw(blur, null, null, BlendMode.DIFFERENCE);
	canvas.draw(canvas, null, null, BlendMode.INVERT);
	canvas.unlock();
}

This is actually an optimized variation on some recent posts that made use of perlin noise. You can get a wide range of effects by changing just the BlendMode values alone…. I particularly like this combination of BlendModes because it reminds me a bit of a terrain map…

Have a look at the swf…

Read snippet: Perlin Outlines

Parallax fp10

[SWF(backgroundColor=0x000000, width = 800, height = 600)]

// this is a trick to keep the 3D texture quality up... 
// try setting it right off the bat and you'll notice that the
// Shapes look pixilated
setTimeout(function():void{ stage.quality="low"}, 500);

var matrix:Matrix = new Matrix();
matrix.createGradientBox(600, 600, 0, -450, -450);

var boxNum:int = 30;
var boxes:Array = [];
for (var i:int = 0; i<boxNum; i++) boxes[i] = makeBox();

var dx:Number = 0, dy:Number = 0;
onLoop();
addEventListener(Event.ENTER_FRAME, onLoop);

function onLoop(evt:Event=null):void {
	dx += (mouseX - dx) / 4;
	dy += (mouseY - dy) / 4;
	for (var i:int = 0; i<boxNum; i++){
		var box:Shape = boxes[i];
		box.z = 400 - i * 20;
		box.x = dx;
		box.y = dy;
		box.rotation = i + getTimer() / 10;
	}
}

function makeBox():Shape{
	var box:Shape = Shape(addChild(new Shape()));
	box.x = stage.stageWidth/2;
	box.y = stage.stageHeight/2;
	box.z = 1;
	with (box.graphics){
		 beginGradientFill(GradientType.RADIAL, [0xFFFFFF, 0x333333], [1,1], [0, 255], matrix, SpreadMethod.PAD);
		drawRect(-100, -100, 200, 200);
		drawRect(-70, -70, 140, 140);
	}
	return box;
}

This snippet draws 30 gradient box shapes, gives them different z values and then moves them based on the mouse. This technique is good if you just want a few layers of parallax motion – I got carried away and you’ll notice that if you add more boxes it begins to slow down pretty quick.


Have a look at the swf….



I first used this technique for this small interactive drawing…

Something interesting I noticed about fp10 3D DisplayObjects is that if you set the stage.quality to low right off the bat, the display objects look pixelated… but if you wait a few milliseconds, you end up with less pixelation and you still get a speed boost from the low quality – I think it must have something to do with the way the 3D textures are handled by the player…

Tomorrow I think I’ll post a version of this that uses IGraphicsData and Utils.projectVectors()… should be a huge speed boost…

Read snippet: Parallax fp10

Another Perlin Texture

var canvas:BitmapData = new BitmapData(1200,1200,false, 0x000000);
addChild(new Bitmap(canvas));

scaleX = scaleY = 0.5;
var w:int = canvas.width 
var hw:int = w / 2;
var hhw:int = hw / 2;
var size:int = canvas.width * canvas.width;

canvas.perlinNoise(hhw,hhw,1,Math.random()*100,false, false, 1, true);

for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	var yp:int = int(i / w);
	var col:uint =  canvas.getPixel(xp, yp) / (-20|i+xp) >> 8 & 0xFF
	canvas.setPixel(xp, yp, col << 16 | col << 8 | col);
}

canvas.applyFilter(canvas, canvas.rect, new Point(0,0), new BlurFilter(4,4,1));
var blur:BitmapData = canvas.clone();
blur.applyFilter(blur, blur.rect, new Point(0,0), new BlurFilter(10,10,1));

canvas.draw(blur, null, null, BlendMode.DARKEN);

This is a variation on yesterdays post. I think it’s time to optimize this and see how it does in real time…

Here is what this snippet will draw:

Read snippet: Another Perlin Texture

Overexposed Perlin Texture

var canvas:BitmapData = new BitmapData(1200,1200,false, 0x000000);
addChild(new Bitmap(canvas));

scaleX = scaleY = 0.5;
var w:int = canvas.width 
var hw:int = w / 2;
var hhw:int = hw / 2;
var size:int = canvas.width * canvas.width;

canvas.perlinNoise(hhw,hhw,2,Math.random()*100,false, false, 1, true);

for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	var yp:int = int(i / w);
	var col:uint =  canvas.getPixel(xp, yp) / (xp+yp-w) >> 8 & 0xFF
	canvas.setPixel(xp, yp, col << 16 | col << 8 | col)
}

var blur:BitmapData = canvas.clone();
blur.applyFilter(blur, blur.rect, new Point(0,0), new BlurFilter(10,10,1));

canvas.draw(blur, null, null, BlendMode.ADD);

I was playing around awhile back and created this snippet, it will draw something that looks like this:

this is one of those snippets that can produce vastly different looking images with minor changes to the code… for instance, try changing the blendMode to darken and line 15 to this:

var col:uint = canvas.getPixel(xp, yp) / (xp|yp-w) >> 5 & 0xFF;

and you’ll end up with this:

…take the original snippet and change the blendMode to subtract:

etc…

Read snippet: Overexposed Perlin Texture

Spring PerspectiveProjection

var pointNum:int = 3000;
x = stage.stageWidth / 2;
y = stage.stageHeight / 2;

var verts:Vector.<Number>  = new Vector.<Number>();
var tVerts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uv:Vector.<Number> = new Vector.<Number>();
var cmds:Vector.<int> = new Vector.<int>();

var index:int = 0;
var half:Number = pointNum / 20000;
for (var i:int = 0; i<pointNum; i+=3){
	verts[i] = 0.08 * Math.cos(i * Math.PI / 180);
	verts[i+1] = 0.08 * Math.sin(i * Math.PI / 180);
	verts[i+2] =  i / 10000 - half;
	cmds[index++] = 2;
}
cmds[0] = 1;

var proj:PerspectiveProjection = new PerspectiveProjection();
proj.fieldOfView = 45;
var projMat:Matrix3D = proj.toMatrix3D();
var m:Matrix3D = new Matrix3D();
var dx:Number = 0, dy:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
       m.identity();
	   dx += (mouseX - dx) / 4;
	   dy += (mouseY - dy) / 4;
	   m.appendRotation(dy,Vector3D.X_AXIS);
	   m.appendRotation(dx,Vector3D.Y_AXIS);
	   m.appendTranslation(0,0,0.5);
	   m.transformVectors(verts, tVerts);
	   Utils3D.projectVectors(projMat, tVerts, pVerts, uv);
	   graphics.clear();
	   graphics.lineStyle(3,0x000000);
	   graphics.drawPath(cmds, pVerts);
}

This snippet draws a spring shape in 3D with perspective. This is the first snippet where I’ve made use of the PerspectiveProjection class. So if your wondering how to add perspective to your Utils3D.projectVectors code… this is one way to do it…


Have a look at the swf…

Read snippet: Spring PerspectiveProjection

Quick Pixel Sphere

var pointNum:int = 20000;
var radius:int = 150;

var canvas:BitmapData = new BitmapData(400,400,false, 0x000000);
addChild(new Bitmap(canvas));
var verts:Vector.<Number>  = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uv:Vector.<Number> = new Vector.<Number>();

for (var i:int = 0; i<pointNum; i+=3){
	var xp:Number = Math.random() * 400 - 200;
	var yp:Number = Math.random() * 400 - 200;
	var zp:Number = Math.random() * 400 - 200;
	var dist:Number = Math.sqrt(xp * xp + yp * yp + zp * zp);
	// normalize and scale x,y,z 
	verts[i] = xp / dist * radius;
	verts[i+1] = yp / dist * radius;
	verts[i+2] = zp / dist * radius;
}

var m:Matrix3D = new Matrix3D();
var dx:Number = 0, dy:Number = 0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
       m.identity();
	   dx += (mouseX - dx) / 4;
	   dy += (mouseY - dy) / 4;
	   m.appendRotation(dx, Vector3D.X_AXIS);
	   m.appendRotation(dy, Vector3D.Y_AXIS);
	   m.appendTranslation(200,200,0);
	   Utils3D.projectVectors(m, verts, pVerts, uv);
	   canvas.fillRect(canvas.rect, 0x000000);
	   for (var i:int = 0; i<pVerts.length; i+=2){
	     canvas.setPixel(pVerts[i], pVerts[i + 1], 0xFFFFFF);
	   }
}

This snippet shows a quick way to randomly place a bunch of xyz coordinates on the surface of a sphere. I saw this trick in an OpenGL book a few years back – dug around my books but couldn’t find it… If I find it I’ll update this post.

The trick is achieved by normalizing the vector defined by each 3D coordinate…


Have a look at the swf…

Read snippet: Quick Pixel Sphere