Latest snippets

Interesting Texture #2

var canvas:BitmapData = new BitmapData(1000,1000,false, 0x000000);
addChild(new Bitmap(canvas));
scaleX = scaleY = .5;

var w:int = canvas.width;
var w10:int = w * 40;
var size:int = canvas.width * canvas.height;
for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	 
	var yp:int = int(i / w);
	var c1:int = (255/8) * (Math.cos(xp* Math.PI/180 * 2) + Math.sin(yp*(xp + 200)/w10));
	if (c1 < 0) c1 = 256 - c1;
	c1 = (c1 << 1 | c1) ;
	canvas.setPixel(xp, yp, c1 <<15 | c1 <<7 | c1 );
}
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var clone:BitmapData = canvas.clone();
canvas.draw(clone, m, null, BlendMode.SUBTRACT);
clone.draw(canvas);
clone.applyFilter(clone, clone.rect, new Point(0,0), new BlurFilter(10,10,1));
canvas.draw(clone, null, null, BlendMode.ADD);

Randomly bit shifting on this one is actually getting a good deal of millage.. I know I can easily optimize so that it works in realtime – could even be done in pixelbender… but going to play a bit more first before I optimize….

Interesting Texture

var canvas:BitmapData = new BitmapData(1000,1000,false, 0x000000);
addChild(new Bitmap(canvas));
scaleX = scaleY = .5;

var w:int = canvas.width;
var w10:int = w * 60;
var size:int = canvas.width * canvas.height;
for (var i:int = 0; i<size; i++){
	var xp:int = i % w;
	 
	var yp:int = int(i / w);
	var c1:int = (255/8) * (Math.cos(xp* Math.PI/180 * 2) + Math.sin(yp*yp/w10));
	if (c1 < 0) c1 = 256 - c1;
	c1 = (c1 << 1 | c1) ;
	canvas.setPixel(xp, yp, c1 <<16 | c1 <<8 | c1 );
}
var m:Matrix = new Matrix();
m.scale(1,-1);
m.translate(0,canvas.height);
var clone:BitmapData = canvas.clone();
canvas.draw(clone, m, null, BlendMode.SUBTRACT);
clone.draw(canvas);
clone.applyFilter(clone, clone.rect, new Point(0,0), new BlurFilter(10,10,1));
canvas.draw(clone, null, null, BlendMode.ADD);

Having one of those days where everything I code doesn’t look right to me… took a little break from other work and created this very unoptimized abstract texture… no animation so here is a bitmap:

Gumdrop Torus

var matrix:Matrix3D = new Matrix3D();
 
var verts:Vector.<Number> = new Vector.<Number>();
var pVerts:Vector.<Number> = new Vector.<Number>();
var uvts:Vector.<Number> = new Vector.<Number>();

for (var i:Number = -2; i<2; i+=.04){
	for (var j:Number = -2; j<2; j+=.04){
		for (var k:Number = -2; k<2; k+=.04){
// equation from: http://local.wasp.uwa.edu.au/~pbourke/geometry/gumdrop/
			var yz:Number = j * j + k * k;
		     var s:Number = 4 * (Math.pow(i,4) + Math.pow(yz,2)) 
			 + 17 * i * i *(yz) - 20 * (yz + i * i) + 17;
			if (s <0 && s > -0.5){
				verts.push(i * 60);
				verts.push(j * 60);
				verts.push(k * 60);
				pVerts.push(0), pVerts.push(0);
				uvts.push(0), uvts.push(0), uvts.push(0);
			 }
		}
	}
}

var tVerts:Vector.<Number> = new Vector.<Number>();
matrix.appendRotation(90, Vector3D.X_AXIS);
matrix.appendRotation(45, Vector3D.Y_AXIS);
matrix.appendScale(1.7, 1.7, 1.7);
matrix.transformVectors(verts, tVerts);

var p:Point = new Point();
var brush:BitmapData=new BitmapData(3,3,true,0x41FFFFFF);
var canvas:BitmapData = new BitmapData(500,500,false, 0x000000);
addChild(new Bitmap(canvas));
var dx:Number=0;
var dy:Number=0;
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	dx += (mouseX - dx)/4;
	dy += (mouseY - dy)/4;
	matrix.identity();
	matrix.appendRotation(dy,Vector3D.X_AXIS);
	matrix.appendRotation(dx,Vector3D.Y_AXIS);
	matrix.appendTranslation(250, 250, 0);
	Utils3D.projectVectors(matrix, tVerts, pVerts, uvts);
	canvas.lock();
	canvas.fillRect(canvas.rect, 0x000000);
	var inc:int = 0;
	for (var i:int = 0; i<pVerts.length; i+=2){
	 
        p.x = pVerts[i];
        p.y = pVerts[i+1];
		canvas.copyPixels(brush, brush.rect, p, null, null, true); 
	}
	canvas.unlock();
}

Felt like revisiting implicit surface plotting today…

Have a look at the swf over at wonderfl.net

Convert Timeline Code to Document Class

For a few different reasons I decided to write some php code to convert timeline code to a document class. The script is done and it seems to work pretty nicely. I’m sure there are a few bugs, but I’ve tested around 30 snippets from this site and they all worked.

To test it out:

1) just take the below code (or any other timeline code), copy it to your clipboard
(The code doesn’t have to be small, I did a test with 300 lines of timeline code and it worked just fine)

x = stage.stageWidth / 2;
y = stage.stageHeight / 2;
var xp:Number = 0, yp:Number = 0;
var r:Number = 0, t:Number = 0;
var speed:Number = .07;
var scale:Number = 20;
var plot0:Shape = Shape(addChild(new Shape()));
var plot1:Shape = Shape(addChild(new Shape()));
plot0.graphics.lineStyle(0,0x000000);
plot1.graphics.lineStyle(0,0x000000);
addEventListener(Event.ENTER_FRAME, onLoop);
function onLoop(evt:Event):void {
	 r =  scale * Math.sqrt(t);
	 xp =  r * Math.cos(t);
	 yp =  r * Math.sin(t);
	 t += speed;
	plot0.graphics.lineTo(xp, yp);
	plot1.graphics.lineTo(-xp, -yp);
}

2) go to this page and follow the instructions:
https://actionsnippet.com/timeline_to_doc.php

I used this script to convert a few snippets from this site to work on wonderfl.net…

Have a look at them here.

In the next few days I may add a button to all code snippets that allows you to convert the code to a doc class…

The script adds import statements automatically, I may however have missed a few packages, so if the generated code is missing an import statement, let me know and I’ll fix it…

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:

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:

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…

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…

Continue reading 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…