Tag: design
A More Interactive Portfolio
I think a portfolio is something that should be very interactive and intuitive. Check out what that has led to: circlecube’s interactive pog portfolio. I’ve been toying with trying to get something that was fun to look at, but also showed some work. Here is a first look at my Interactive portfolio of work which includes physics simulations and many options to play with the presentation of the body of work. Showing it to a friend he said it made him think of pogs (since the thumbnails are round and moving everywhere).
Well, enough, I’ll let you see what you see… Interactive POG Portfolio
The details
Well, if you’re interested, this is the same portfolio that is listed statically on my website. That’s because I’m using amfphp to read my wordpress database and get the custom post type of portfolio and access all the tags, images and details of each portfolio item. I’m using TweenNano from greensock for some of the motion but all the physics is coded in as3. I’m using the slider and switch from Nick Jonas.
Enjoy playing with the settings!
Now I’m thinking of other ways to implement it: specifically hooking into API services like last.fm, dribbble or twitter. Or rebuild it with jQuery and html5!
Interactive Generative Art Series – 08 – multiple lines scalable
Well, so much for blogging each step in my process of creating this generative art series. I took a few steps in this iteration since the last one. But it was all in the spirit of one step. First I wanted to abstract the duplication of each ball/line so that it didn’t require copying blocks of code for each one. The obvious route is to have a var that designates the number of balls which will draw lines, and then loop through creating the desired number and then in the loop function that is executed each frame loop through them again and draw new lines for each one. This was pretty simple, in the end, and I ended up adding quite a few variables to differentiate each line for the others in line width, color variation and position. I also added a few function to help with calculations and updated the alpha values of the lines. The normalize, interpolate and map functions I acquired long ago from kp here, go there to hear his explanation which is much better than any attempt I could make. Thanks Keith!
Then, I had the task of making it more manageable and scalable. Before these edits, the framerate would sink to around 6 in the first 10 seconds of running with more than 3 lines. After some research it seemed the performance suffered mainly because the graphics drawn with transparency had to figure every single line on the stage to determine it’s color values and flash doesn’t do that too efficiently. So the solution was to use the bitmap and bitmapdata objects. Every frame I copy what has been drawn on the stage into a bitmapdata objects and set it to display on the stage instead. This essentially lets flash calculate the alpha values for each line once and then copy it as simple pixel data for later frames. It happens every frame and is in the flush function. It worked better than I had hoped. I could ramp up the number of lines to 40 and still not see any frame rate slowdown in FPS.
08 multiple lines scalable, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart8a” movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/03/gen-art-08-multiple-lines-scalable.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
08 multiple lines scalable, another instance
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart8b” movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/03/gen-art-08-multiple-lines-scalable.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var balls:Array = new Array(); // array of ball objects – each ball object stores it’s own position (current & previous), acceleration, etc
var num_balls:int = 0;
var total_balls:int = 12;
var canvas:Sprite = new Sprite();
this.addChild(canvas);
//copy the graphics on stage to a bitmap, then next frame draw on it.
var bitmapcanvasdata:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, true, 0x000000);
//draw stage to bitmap
bitmapcanvasdata.draw(canvas);
var bitmapcanvas:Bitmap = new Bitmap(bitmapcanvasdata);
//put bitmap on stage
this.addChild(bitmapcanvas);
function createBall():void{
var ball_o:Object = new Object();
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, .5);
ball.graphics.drawCircle(0, 0, 3);
ball.graphics.endFill();
addChild(ball);
ball_o.ball = ball;
ball_o.x = randomRangeAxis(10);
ball_o.y = 0;
ball_o.ax = 0;
ball_o.ay = 0;
ball_o.oldx = ball_o.ball.x;
ball_o.oldy = ball_o.ball.y;
ball_o.gradientBoxMatrix = new Matrix();
ball_o.drift = randomRangeAxis(10);
ball_o.color_drift = Math.floor(randomRangeAxis(4)) * 1024;
ball_o.line_width_drift = randomRangeAxis(2);
balls.push(ball_o);
}
for (var i:int = 0; i < total_balls; i++){
createBall();
}var anchor:Sprite = new Sprite();anchor.graphics.beginFill(0x333333, .6);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);var div:Number = .1;
var line_max_width:Number = 64;
var line_min_width:Number = 1;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;var anchorvx:Number = 0;
var anchorvy:Number = 0;anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;var colors:Object = new Object();
colors.r = 150;
colors.g = 100;
colors.b = 200;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rd = 100;
colors.gd = 150;
colors.bd = 200;
colors.rmin = randomRange(0, 30); //0
colors.rmax = randomRange(colors.rmin, colors.rmin + colors.rd); //100
colors.gmin = randomRange(0, 60); //100
colors.gmax = randomRange(colors.gmin, colors.gmin + colors.gd); //200
colors.bmin = randomRange(0, 50); //150
colors.bmax = randomRange(colors.bmin, colors.bmin + colors.bd); //250
colors.rate_of_change = 10;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);function loop (e:Event = null) {
//anchor
anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);
anchor.x += anchorvx;
anchor.y += anchorvy;
anchorvx *= dampen;
anchorvy *= dampen;
if(anchor.x > stage.stageWidth) anchor.x = 0 – anchor.width;
else if(anchor.x < 0 - anchor.width) anchor.x = stage.stageWidth;
if(anchor.y > stage.stageHeight) anchor.y = 0 – anchor.height;
else if(anchor.y < 0 - anchor.height) anchor.y = stage.stageHeight;
//linewidth
line_width_velocity += randomRangeAxis(1);
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}
//color step
color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);
//loop through balls and draw lines
for (var i:int = 0; i < total_balls; i++){
balls[i].oldx = balls[i].ball.x;
balls[i].oldy = balls[i].ball.y;
balls[i].ball.x -= balls[i].ax = (balls[i].ax + (balls[i].ball.x - (anchor.x + randomRangeAxis(line_width * balls[i].drift))) * div) * .9;
balls[i].ball.y -= balls[i].ay = (balls[i].ay + (balls[i].ball.y - (anchor.y + randomRangeAxis(line_width * balls[i].drift))) * div) * .9;
balls[i].dx = balls[i].x - balls[i].oldx;
balls[i].dy = balls[i].y - balls[i].oldy;
canvas.graphics.moveTo(balls[i].oldx, balls[i].oldy);
canvas.graphics.lineStyle(randomRangeAxis(balls[i].line_width_drift,line_width), color_first, 1, true, LineScaleMode.NONE, CapsStyle.NONE);
balls[i].gradientBoxMatrix.createGradientBox(Math.abs(balls[i].dx), Math.abs(balls[i].dy), Math.atan2(balls[i].dy,balls[i].dx), Math.min(balls[i].oldx, balls[i].ball.x), Math.min(balls[i].oldy, balls[i].ball.y));
canvas.graphics.lineGradientStyle(GradientType.LINEAR, [color_first + balls[i].color_drift, color_second + balls[i].color_drift], [map(line_width,line_max_width,line_min_width, .1, .9),map(line_width,line_max_width,line_min_width, .1, .9)], [0, 255], balls[i].gradientBoxMatrix);
canvas.graphics.lineTo(balls[i].ball.x, balls[i].ball.y);
}
//copy graphics drawings to bitmapdata and clear graphics
flush();
}
function flush():void {
//draw stage to bitmap
bitmapcanvasdata.draw(canvas);
//replace bitmapdata of bitmap
bitmapcanvas.bitmapData = bitmapcanvasdata;
//erase vectors on stage
canvas.graphics.clear();
}this.addEventListener(Event.ENTER_FRAME, loop)function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b);
}
function color_step(){
colors.rv += randomRangeAxis(colors.rate_of_change);
colors.r += colors.rv;
colors.rv *= dampen;
if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){
colors.r = colors.rmin;
}
colors.gv += randomRangeAxis(colors.rate_of_change);
colors.g += colors.gv;
colors.gv *= dampen;
if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){
colors.g = colors.gmin;
}
colors.bv += randomRangeAxis(colors.rate_of_change);
colors.b += colors.bv;
colors.bv *= dampen;
if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){
colors.b = colors.bmin;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max - min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number, axis:Number = 0):Number {
return Math.random() * (max * 2) - max + axis;
}
//normalize(value, min, max) takes a value within a given range and converts it to a number between 0 and 1 (actually it can be outside that range if the original value is outside its range).
function normalize(value:Number, minimum:Number, maximum:Number):Number {
return (value - minimum) / (maximum - minimum);
}
//interpolate(min, max, value) is linear interpolation. It takes a normalized value and a range and returns the actual value for the interpolated value in that range.
function interpolate(normValue:Number, minimum:Number, maximum:Number):Number {
return minimum + (maximum - minimum) * normValue;
}
//map(value, min1, max1, min2, max2) takes a value in a given range (min1, max1) and finds the corresonding value in the next range(min2, max2).
function map(value:Number, min1:Number, max1:Number, min2:Number, max2:Number):Number {
return interpolate( normalize(value, min1, max1), min2, max2);
}
[/cc]
download
Here’s the gen-art-08-multiple-lines-scalable.swf as well as the gen-art-08-multiple-lines-scalable.fla to download and explore. And as always if you’ve got ideas or suggestions, comment below. One thing I’m struggling with is that now although the experiment is truly generative, it’s no longer interactive.
Interactive Generative Art Series – 07 – multiple lines
To make it more interesting and give more depth and texture to the display, I wanted to have more lines than one, so I’m now going with two for starters. Eventually I’d like to get up to a dozen or maybe even have them randomly self populate and die over time. Adding one more isn’t a whole lot of code, but it did require a bit of rearranging. I created a sprite container for each line, and then basically doubled any var used by one line for the other. When calculating the position for the second line I added a bit of randomness, so it wouldn’t be drawn in the exact same position of the first line. Plus, when drawing the second line I adjust the alpha/transparency a bit and the line width. A big issues that I notice right away is that the memory noticeably begins to suffer after a bit of drawing. After some investigation I determined it is (at least in part) the fact that the lines now have to blend with the lines below them with transparency. If I set the alpha properties in the lineGradientStyle to 1 and 1 the performance is much better. Any ideas of how to fix this? I’m guessing I should start investigating bitmap data.
07 multiline, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart7″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/03/gen-art-07-multilines.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, 1);
ball.graphics.drawCircle(0, 0, 10);
ball.graphics.endFill();
addChild(ball);
var ball2:Sprite = new Sprite();
ball2.graphics.beginFill(0x000000, 1);
ball2.graphics.drawCircle(0, 0, 5);
ball2.graphics.endFill();
addChild(ball2);
var balllines:Sprite = new Sprite();
addChild(balllines);
var ball2lines:Sprite = new Sprite();
addChild(ball2lines);
var anchor:Sprite = new Sprite();
anchor.graphics.beginFill(0x333333, .6);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);
var div:Number = .1;
var line_max_width:Number = 64;
var line_min_width:Number = 1;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;
var ball2ax:Number = 0;
var ball2ay:Number = 0;
var old2x:Number = ball2.x;
var old2y:Number = ball2.y;
var anchorvx:Number = 0;
var anchorvy:Number = 0;
anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;
ball2.x = randomRangeAxis(10);
var gradientBoxMatrix:Matrix = new Matrix();
var colors:Object = new Object();
colors.r = 255;
colors.g = 255;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rmin = 150; //0
colors.rmax = 250; //100
colors.gmin = 0; //100
colors.gmax = 150; //200
colors.bmin = 0; //150
colors.bmax = 100; //250
colors.rate_of_change = 12;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
function loop () {
oldx = ball.x;
oldy = ball.y;
old2x = ball2.x;
old2y = ball2.y;
anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);
anchor.x += anchorvx;
anchor.y += anchorvy;
anchorvx *= dampen;
anchorvy *= dampen;
if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 - anchor.width) {
anchor.x = stage.stageWidth;
}
if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 - anchor.height) {
anchor.y = stage.stageHeight;
}
ball.x -= ballax = (ballax + (ball.x - anchor.x) * div) * .9;
ball.y -= ballay = (ballay + (ball.y - anchor.y) * div) * .9;
ball2.x -= ball2ax = (ball2ax + (ball2.x - (anchor.x + randomRangeAxis(line_width * 2))) * div) * .9;
ball2.y -= ball2ay = (ball2ay + (ball2.y - (anchor.y + randomRangeAxis(line_width * 2))) * div) * .9;
line_width_velocity += randomRangeAxis(1);
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}
color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);
var dx:Number = ball.x - oldx;
var dy:Number = ball.y - oldy;
balllines.graphics.lineStyle(line_width, color_first, (line_width+100-line_max_width)/100, true, LineScaleMode.NONE, CapsStyle.NONE);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
balllines.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [(line_width+100-line_max_width)/100,(line_width+100-line_max_width)/100], [0, 255], gradientBoxMatrix);
balllines.graphics.lineTo(ball.x, ball.y);
dx = ball2.x - old2x;
dy = ball2.y - old2y;
ball2lines.graphics.lineStyle(line_width/2, color_first, (line_width+100-line_max_width)/100, true, LineScaleMode.NONE, CapsStyle.NONE);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(old2x, ball2.x), Math.min(old2y, ball2.y));
ball2lines.graphics.lineGradientStyle(GradientType.LINEAR, [color_first + 3072, color_second + 3072], [((line_width/2)+100-line_max_width)/100,((line_width/2)+100-line_max_width)/100], [0, 255], gradientBoxMatrix);
ball2lines.graphics.lineTo(ball2.x, ball2.y);
}setInterval(loop, 1000/30);function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b);
}
function color_step(){
colors.rv += randomRangeAxis(colors.rate_of_change);
colors.r += colors.rv;
colors.rv *= dampen;
if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){
colors.r = colors.rmin;
}
colors.gv += randomRangeAxis(colors.rate_of_change);
colors.g += colors.gv;
colors.gv *= dampen;
if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){
colors.g = colors.gmin;
}
colors.bv += randomRangeAxis(colors.rate_of_change);
colors.b += colors.bv;
colors.bv *= dampen;
if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){
colors.b = colors.bmin;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max - min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number, axis:Number = 0):Number {
return Math.random() * (max * 2) - max + axis;
}
[/cc]
download
Here’s the gen-art-07-multilines.swf as well as the gen-art-07-multilines.fla to download and tinker.
Interactive Generative Art Series – 06 – lineStyle
The last example in this series discussed getting the anchor to move in a way that our ball would paint more interesting and we worked on restricting the colors to a certain RGB range. This one is a very simple change, but has a pretty significant effect. We’re just editing the cap style of our lines in lineStyle. The default value we’ve been using so far is ROUND, but now if we test NONE the lines drawn will have no ends and basically be rectangles (since the width is so wide). This gets interesting especially when the path curves and we can see all the angles and corners exposed by the rectangles and it makes me think of a wooden snake toy (Wooden Wiggle Snake). I started playing around with the opacity or alpha property of the lines as well so that the flat ended lines would show better. What else would you toy with in here?
06 lineStyle, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”gen-art-6″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-06-linestyle.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, 1);
ball.graphics.drawCircle(0, 0, 10);
ball.graphics.endFill();
addChild(ball);
var anchor:Sprite = new Sprite();
anchor.graphics.beginFill(0x333333, .6);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);
var div:Number = .1;
var line_max_width:Number = 64;
var line_min_width:Number = 2;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;
var anchorvx:Number = 0;
var anchorvy:Number = 0;
anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;
var gradientBoxMatrix:Matrix = new Matrix();
var colors:Object = new Object();
colors.r = 255;
colors.g = 255;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rmin = 0;
colors.rmax = 150;
colors.gmin = 100;
colors.gmax = 200;
colors.bmin = 200;
colors.bmax = 250;
colors.rate_of_change = 12;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
function loop () {
oldx = ball.x;
oldy = ball.y;
anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);
anchor.x += anchorvx;
anchor.y += anchorvy;
anchorvx *= dampen;
anchorvy *= dampen;
if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 - anchor.width) {
anchor.x = stage.stageWidth;
}
if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 - anchor.height) {
anchor.y = stage.stageHeight;
}
ball.x -= ballax = (ballax + (ball.x - anchor.x) * div) * .9;
ball.y -= ballay = (ballay + (ball.y - anchor.y) * div) * .9;
line_width_velocity += randomRangeAxis(1);
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}
color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);
var dx:Number = ball.x - oldx;
var dy:Number = ball.y - oldy;
this.graphics.lineStyle(line_width, color_first, (line_width+100-line_max_width)/100, true, LineScaleMode.NONE, CapsStyle.NONE);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [(line_width+100-line_max_width)/100,(line_width+100-line_max_width)/100], [0, 255], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}setInterval(loop, 1000/30);function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b);
}
function color_step(){
colors.rv += randomRangeAxis(colors.rate_of_change);
colors.r += colors.rv;
colors.rv *= dampen;
if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){
colors.r = colors.rmin;
}
colors.gv += randomRangeAxis(colors.rate_of_change);
colors.g += colors.gv;
colors.gv *= dampen;
if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){
colors.g = colors.gmin;
}
colors.bv += randomRangeAxis(colors.rate_of_change);
colors.b += colors.bv;
colors.bv *= dampen;
if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){
colors.b = colors.bmin;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max - min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number, axis:Number = 0):Number {
return Math.random() * (max * 2) - max + axis;
}
[/cc]
download
Here’s the gen-art-06-linestyle.swf as well as the gen-art-06-linestyle.fla to download and tinker.
Reference
Interactive Generative Art Series – 05 – wild anchor
While in the previous step (Generative Art 04 Using a target other than the mouse) in this generative actionscript art tutorial series it was cool to see everything move on it’s very own, it seemed a bit slow or fake, or maybe just plain uninteresting. Tinkering with the color, I thought if we set a minimum and maximum value for each red green and blur we could control the colors a bit more and still let them be generative. Plus I wanted the anchor to move a bit more and thus paint the curves and lines in a more interesting fashion. To do this we ramp up the range of the change rate of the anchor velocity. I really enjoy this example because it is faster, so we get more of those sweeping arcs, but also when the anchor slows down we get some very delicate curves and twists. With just a couple changes from the last example (which frankly seemed a bit chaotic), now I’m starting to see for the first time how to set some controls in the code which will lead to a visually appealing and still randomly generative result.
For some reason I find it gratifying that the final swf is still a mere 2kb and change. Perhaps all this current focus on HD and 3D gives us the sense that to be good it needs to have a large footprint. Sometimes the magic or value is in how much you can accomplish with less (less is more)
05 Wild Anchor, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-05-wild-anchor.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, .5);
ball.graphics.drawCircle(0, 0, 5);
ball.graphics.endFill();
addChild(ball);
var anchor:Sprite = new Sprite();
anchor.graphics.beginFill(0x333333, .5);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);
var div:Number = .1;
var line_max_width:Number = 48;
var line_min_width:Number = 1;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;
var anchorvx:Number = 0;
var anchorvy:Number = 0;
anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;
var colors:Object = new Object();
colors.r = 255;
colors.g = 255;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.rmin = 150; //0
colors.rmax = 250; //100
colors.gmin = 0; //100
colors.gmax = 150; //200
colors.bmin = 0; //150
colors.bmax = 100; //250
colors.rate_of_change = 12;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
var gradientBoxMatrix:Matrix = new Matrix();
function loop () {
oldx = ball.x;
oldy = ball.y;
anchorvx += randomRangeAxis(10);
anchorvy += randomRangeAxis(10);
anchor.x += anchorvx;
anchor.y += anchorvy;
anchorvx *= dampen;
anchorvy *= dampen;
if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 – anchor.width) { anchor.x = stage.stageWidth; } if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 – anchor.height) { anchor.y = stage.stageHeight; } ball.x -= ballax = (ballax + (ball.x – anchor.x) * div) * .9; ball.y -= ballay = (ballay + (ball.y – anchor.y) * div) * .9; line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}
color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);
var dx:Number = ball.x – oldx;
var dy:Number = ball.y – oldy;
this.graphics.lineStyle(line_width);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [1,1], [0, 255], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}
setInterval(loop, 1000/30);
function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(colors.rate_of_change); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.rmax) {
colors.r = colors.rmax;
} else if (colors.r < colors.rmin){ colors.r = colors.rmin; } colors.gv += randomRangeAxis(colors.rate_of_change); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.gmax) {
colors.g = colors.gmax;
} else if (colors.g < colors.gmin){ colors.g = colors.gmin; } colors.bv += randomRangeAxis(colors.rate_of_change); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.bmax) {
colors.b = colors.bmax;
} else if (colors.b < colors.bmin){
colors.b = colors.bmin;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max – min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number):Number {
return Math.random() * (max * 2) – max;
}
[/cc]
download
View the swf and get the fla source file.
Interactive Generative Art Series – 04 – anchor
Thanks for keeping up with this random generative art series. I know I’m having a ball just playing with code one step at a time. To watch each iteration, I was getting tired of drawing with my mouse to see the generative art, and as others had pointed out, in order for it to truly be generative, it shouldn’t depend on me moving my mouse. So instead of using the mouse position as my target anchor, I created a new node named anchor. This anchor I’m animating with simple random brownian motion which I’ve blogged about before. It just meanders along the stage as it pleases and the other ball will “chase” it just like it chased your mouse in the previous examples. The part that gets exciting is that my anchor wraps from one side of the stage to the other, while the ball does not. One second it’s target is far right and the next it switches to far left, this makes for some really interesting paths and lines. Experiment with the velocity of the anchor in lines 47 + 48 to see interesting effects. One thing I’m beginning to notice however is the performance of the little app gets a bit slower the longer you let it run, perhaps I didn’t realize it before since I didn’t have the attention to keep moving my mouse and watching it follow, now that it truly is generative (and less interactive btw), I watch it longer (seems kind of backwards to what I’d expect).
Note: in this example I have the anchor ball visible, as well as the other ball, but for an actual production, I’d have them both hidden and the lines just appearing. I prefer it that way but though you’d better see what was actually happening with them visible, even though it kills some of the magic. It’s like watching a magic trick when you already know how it’s done.
04 Anchor, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”gen-art-4″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-04-anchor.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x000000, 0);
ball.graphics.drawCircle(0, 0, 5);
ball.graphics.endFill();
addChild(ball);
var anchor:Sprite = new Sprite();
anchor.graphics.beginFill(0x333333, 0);
anchor.graphics.drawCircle(0, 0, 12);
anchor.graphics.endFill();
addChild(anchor);
var div:Number = .1;
var line_max_width:Number = 42;
var line_min_width:Number = 2;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var ballax:Number = 0;
var ballay:Number = 0;
var oldx:Number = ball.x;
var oldy:Number = ball.y;
var anchorvx:Number = 0;
var anchorvy:Number = 0;
anchor.x = stage.stageWidth/2;
anchor.y = stage.stageHeight/2;
var colors:Object = new Object();
colors.r = 0;
colors.g = 122;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.min = 0;
colors.max = 200;
var color_first:Number = 0xFFFFFF;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
var gradientBoxMatrix:Matrix = new Matrix();
function loop ()
{
oldx = ball.x;
oldy = ball.y;
anchorvx += randomRangeAxis(2);
anchorvy += randomRangeAxis(2);
anchor.x += anchorvx;
anchor.y += anchorvy;
anchorvx *= dampen;
anchorvy *= dampen;
if(anchor.x > stage.stageWidth) {
anchor.x = 0 – anchor.width;
}
else if(anchor.x < 0 – anchor.width) { anchor.x = stage.stageWidth; } if(anchor.y > stage.stageHeight) {
anchor.y = 0 – anchor.height;
}
else if(anchor.y < 0 – anchor.height) { anchor.y = stage.stageHeight; } ball.x -= ballax = (ballax + (ball.x – anchor.x) * div) * .9; ball.y -= ballay = (ballay + (ball.y – anchor.y) * div) * .9; line_width_velocity += randomRangeAxis(1); line_width += line_width_velocity; line_width_velocity *= dampen; if(line_width > line_max_width) {
line_width = line_max_width;
line_width_velocity = 0;
}
else if (line_width < line_min_width) {
line_width = line_min_width;
line_width_velocity = 0;
}
color_step();
color_first = color_second;
color_second = rgb2hex(colors.r, colors.g, colors.b);
var dx:Number = ball.x – oldx;
var dy:Number = ball.y – oldy;
this.graphics.lineStyle(line_width);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [1,1], [85, 170], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}
setInterval(loop, 1000/30);
function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += Math.random() * 20 – 10; colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.max) {
colors.r = colors.max;
} else if (colors.r < colors.min){ colors.r = colors.min; } colors.gv += Math.random() * 20 – 10; colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.max) {
colors.g = colors.max;
} else if (colors.g < colors.min){ colors.g = colors.min; } colors.bv += Math.random() * 20 – 10; colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.max) {
colors.b = colors.max;
} else if (colors.b < colors.min){
colors.b = colors.min;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max – min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number):Number {
return Math.random() * (max * 2) – max;
}
[/cc]
download
swf and fla source file.
Interactive Generative Art Series – 03 – Gradient Colors
With the full range of colors randomly available to me, I wanted to get a more fluid randomly created color. I see the hard line breaking one color from the next in the generative art 02 random color experiment. I wanted to have the lines drawn between my 2 points to be a gradient of two colors rather than solid color followed by solid color. In this attempt at a smoother color transition, I needed to better understand the gradientBoxMatrix and createGradientBox. I knew visually what I wanted to accomplish but had to brush up on the docs and then experiment a bit to get the math right. The hard line color change still shows in places, but it’s only when one line is short enough and then is overwritten by the beginning of the next line, so technically it’s doing what I intended, but visually it’s still not as gradual as I was wanting. I could toy a bit more with the rate of color change, but I feel pretty accomplished after having figured out that trigonometry and arc-tangent.
03 Gradient Color, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”genart-3″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-03-gradient-color.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x333333, 1);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);
var oldx:Number = ball.x;
var oldy:Number = ball.y;
var div:Number = .1;
var ax:Number = 0;
var ay:Number = 0;
var line_max_width:Number = 75;
var line_min_width:Number = 5;
var line_width:Number = randomRange(line_min_width, line_max_width);
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var colors:Object = new Object();
colors.r = 0;
colors.g = 122;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
colors.min = 0;
colors.max = 155;
var color_first:Number = 0x000000;
var color_second:Number = rgb2hex(colors.r, colors.g, colors.b);
var gradientBoxMatrix:Matrix = new Matrix();
function loop () {
oldx = ball.x;
oldy = ball.y;
ball.x -= ax = (ax + (ball.x – mouseX) * div) * .9;
ball.y -= ay = (ay + (ball.y – mouseY) * div) * .9;
line_width_velocity += randomRangeAxis(3);
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) { line_width = line_max_width; }
if (line_width < line_min_width) { line_width = line_min_width; }
color_first = color_second;
color_step();
color_second = rgb2hex(colors.r, colors.g, colors.b);
var dx:Number = ball.x – oldx;
var dy:Number = ball.y – oldy;
this.graphics.lineStyle(line_width);
gradientBoxMatrix.createGradientBox(Math.abs(dx), Math.abs(dy), Math.atan2(dy,dx), Math.min(oldx, ball.x), Math.min(oldy, ball.y));
this.graphics.lineGradientStyle(GradientType.LINEAR, [color_first, color_second], [1,1], [85, 170], gradientBoxMatrix);
this.graphics.lineTo(ball.x, ball.y);
}
setInterval(loop, 1000/30);
function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += randomRangeAxis(10); colors.r += colors.rv; colors.rv *= dampen; if (colors.r > colors.max) {
colors.r = colors.max;
} else if (colors.r < colors.min){ colors.r = colors.min; } colors.gv += randomRangeAxis(10); colors.g += colors.gv; colors.gv *= dampen; if (colors.g > colors.max) {
colors.g = colors.max;
} else if (colors.g < colors.min){ colors.g = colors.min; } colors.bv += randomRangeAxis(10); colors.b += colors.bv; colors.bv *= dampen; if (colors.b > colors.max) {
colors.b = colors.max;
} else if (colors.b < colors.min){
colors.b = colors.min;
}
}
//random number between min and max
function randomRange(max:Number, min:Number = 0):Number {
return Math.random() * (max – min) + min;
}
//random number range centered at 0 with the specified max, randomRange(-max, max)
function randomRangeAxis(max:Number):Number {
return Math.random() * (max * 2) – max;
}
[/cc]
You’ll see I introduced a few new methods into this example. I wanted to simplify my random number generation so I created a couple separate functions to create a random number within a certain range, one given a min and max and another to give a random range around an axis, so for example a number between -10 and +10.
download
Here’s the gen-art-03-gradient-color.swf and gen-art-03-gradient-color.fla.
Resources
Interactive Generative Art Series – 02 – Random Color
With this example we’re taking a look at having randomly changing color. I liked the limits to the color in the last post, but couldn’t help myself and wanted to see it with the full range of colors to command. Also, I wasn’t a huge fan when the color would “wrap” and jump from one color to the next so fast. I wanted to use the same velocity (rate of change) principle from the line width experiment but apply it to color, and have it meander aimlessly among all colors. I created a color object to store a value for each of the RGB color values, and then had each element of the color change independently. I didn’t want to complicate my loop function so I made a new function that is called from loop that steps along to a color which should be pretty close to the previous color. I enjoy the range, but as I expected it was a bit much, or too many colors at once, also the step is a bit too fast at times it seems.
02 Color, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/02/gen-art-02-color.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
actionscript source code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x333333, 1);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);
var div:Number = .1;
var ax:Number = 0;
var ay:Number = 0;
var line_max_width:Number = 50;
var line_min_width:Number = 0;
var line_width:Number = Math.random() * line_max_width;
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var colors:Object = new Object();
colors.r = 0;
colors.g = 0;
colors.b = 255;
colors.rv = 0;
colors.gv = 0;
colors.bv = 0;
function loop () {
ball.x -= ax = (ax + (ball.x – mouseX) * div) * .9;
ball.y -= ay = (ay + (ball.y – mouseY) * div) * .9;
line_width_velocity += Math.random() * 6 – 3;
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) { line_width = line_max_width; }
if (line_width < line_min_width) { line_width = line_min_width; }
color_step();
this.graphics.lineStyle(line_width, rgb2hex(colors.r, colors.g, colors.b), 1);
this.graphics.lineTo(ball.x, ball.y);
}
setInterval(loop, 1000/30);
function rgb2hex(r:Number, g:Number, b:Number):Number {
return(r<<16 | g<<8 | b); } function color_step(){ colors.rv += Math.random() * 20 – 10; colors.r += colors.rv; colors.rv *= dampen; if (colors.r > 255) {
colors.r = 255;
} else if (colors.r < 0){ colors.r = 0; } colors.gv += Math.random() * 20 – 10; colors.g += colors.gv; colors.gv *= dampen; if (colors.g > 255) {
colors.g = 255;
} else if (colors.g < 0){ colors.g = 0; } colors.bv += Math.random() * 20 – 10; colors.b += colors.bv; colors.bv *= dampen; if (colors.b > 255) {
colors.b = 255;
} else if (colors.b < 0){
colors.b = 0;
}
}
[/cc]
Download
Interactive Generative Art Series – 01 – Color
After updating the line width to be still random, but more of a gradual step in variation (in the first experiment in this series), the second most obvious edit to the original in this generative art series is the color of the line. While it would be pretty simple to update the code to use any one solid color in place of the black, I wanted the color to vary over time. The simplest way I know to achieve this is to create a variable to hold the color value (as a number) and then change it over time. So here, I have a color chosen at random and just increment it every time the loop function executes by 1024. I chose this amount because it would loop through and eventually get back to where it started while restricting the color scheme. I think it brings a lot to the design to have color – and I especially like how it randomly creates a color scheme and sticks to it. Totally random colors may look a bit much, while problematically it’s not too difficult to get, it may be difficult to look at once it’s created. Above are a few screen shots of the random colors generated:
01 Color, play here
[kml_flashembed publishmethod=”dynamic” fversion=”9.0.0″ replaceId=”gen-art-01″ movie=”https://circlecube.com/circlecube/wp-content/uploads/sites/10/2011/01/gen-art-01-color.swf” width=”550″ height=”550″ targetclass=”flashmovie”]
Please visit the blog article to view this interactive flash content. Flash plug-in required:
[/kml_flashembed]
Source Code
[cc lang=”actionscript”]
var ball:Sprite = new Sprite();
ball.graphics.beginFill(0x333333, 1);
ball.graphics.drawCircle(0, 0, 30);
ball.graphics.endFill();
addChild(ball);
var div:Number = .1;
var ax:Number = 0;
var ay:Number = 0;
var line_max_width:Number = 50;
var line_min_width:Number = 0;
var line_width:Number = Math.random() * line_max_width;
var line_width_velocity:Number = 0;
var dampen:Number = 0.95;
var color:Number = Math.floor(Math.random() * 16777215);
function loop () {
ball.x -= ax = (ax + (ball.x – mouseX) * div) * .9;
ball.y -= ay = (ay + (ball.y – mouseY) * div) * .9;
line_width_velocity += Math.random() * 6 – 3;
line_width += line_width_velocity;
line_width_velocity *= dampen;
if(line_width > line_max_width) { line_width = line_max_width; }
if (line_width < line_min_width) { line_width = line_min_width; }
this.graphics.lineStyle(line_width, color+=1024, 1);
this.graphics.lineTo(ball.x, ball.y);
}
setInterval(loop, 1000/30);
[/cc]
You’ll see if you’re following along that this only add 2 lines of code from the last version. We simply create and instantiate (with a random value) the color variable and then apply it in place of the black to the lineStyle and simultaneously increment it. Check the example swf here and get the fla here.