Posted: January 8th, 2010 | Author: admin | Filed under: Uncategorized | 8 Comments »
One of the challanges in the design of www.flurrious.com was getting those circular sliders in. Of course you can fake it and create an animation of a slider and control the timeline from 0-100, but that’s lame and not so easy to modify (like change the radius, sweep angle etc.). so, I set to create a circular slider.
I had the basic principles in place: create a circle, and create a beginSwipe andgle and an endSwipe angle. done:

the code looks something like this:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.Event;
/**
* @author iasseo
*/
public class CircularSlider extends MovieClip
{
private var _circ : Sprite;
private var _startAngle : Number = 90;
private var _angleRange : Number = 30;
private var _angleShape : Sprite;
private var _radius : Number = 250;
private var topAngle : Number;
private var bottmAngle : Number;
public function CircularSlider()
{
calcAngles();
drawCircle();
initAngle();
addEventListener(Event.ENTER_FRAME, onEF);
}
private function calcAngles() : void
{
topAngle = _startAngle - _angleRange - 90;
topAngle = topAngle / 180 * Math.PI;
bottmAngle = _startAngle + _angleRange - 90;
bottmAngle = bottmAngle / 180 * Math.PI;
}
private function initAngle() : void
{
_angleShape = new Sprite();
_angleShape.x = stage.stageWidth/2;
_angleShape.y = stage.stageHeight/2;
addChild(_angleShape);
}
private function drawAngle() : void
{
_angleShape.graphics.lineStyle(2, 0xff0000);
_angleShape.graphics.lineTo(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius);
_angleShape.graphics.lineStyle(2, 0x00ff00);
_angleShape.graphics.lineTo(Math.cos(bottmAngle)*_radius, Math.sin(bottmAngle)*_radius);
_angleShape.graphics.lineStyle(2, 0xff0000);
_angleShape.graphics.lineTo(0, 0);
}
private function drawCircle() : void
{
_circ = new Sprite();
_circ.graphics.lineStyle(1,0xffffff);
_circ.graphics.drawCircle(0, 0, _radius);
_circ.graphics.endFill();
_circ.x = stage.stageWidth/2;
_circ.y = stage.stageHeight/2;
addChild(_circ);
}
private function onEF(e:Event):void
{
_angleRange = Math.abs(stage.stageHeight/2 - mouseX);
_angleShape.graphics.clear();
calcAngles();
drawAngle();
}
}
}
Next, I needed to place the scroll handlebar at the top of the sweep (top of green line in picture), and have it be draggable to the bottom of the sweep. To do that, I calculated the X,Y position of the top and bottom (which I already have in the code), and upon click, I created a rectangle that represented the bounding box for the drag operation. Then, I calculated the percentage point of the handle inside that bounding box to get the 0-1 result, and using the Y position, extracted what the X position would be:

The only problem is that now, when I remove the guides (the circle and angles), I am left with only the slider… and I need the arc so the slider has some visual representation. There are 2 solutions for that. Simple solution: mask the circle… easy to do. here’s the result:

A solution that’s a bit more complex is to DRAW the arc.. that’s where I was happy to find this nice post by the algorythmist. So, using this code, you can then create a nice circular slider:

now all that’s left to do is output the percentage from the slider and you got yourself a nice circular slider!
here’s the final code:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.geom.Rectangle;
/**
* @author iasseo
*/
public class CircularSlider extends MovieClip
{
private var _circ : Sprite;
private var _startAngle : Number = 90;
private var _angleRange : Number = 30;
private var _angleShape : Sprite;
private var _radius : Number = 250;
private var topAngle : Number;
private var bottmAngle : Number;
private var _handle : Sprite;
private var _box : Sprite;
private var _handleHolder : Sprite;
private var _mask : Sprite;
public function CircularSlider()
{
calcAngles();
drawCircle();
initAngle();
drawAngle();
drawSegments();
createHandle();
}
private function createHandle() : void
{
_handleHolder = new Sprite();
_handleHolder.x = stage.stageWidth/2;
_handleHolder.y = stage.stageHeight/2;
addChild(_handleHolder);
_handle = new Sprite();
_handle.graphics.beginFill(0xcccccc);
_handle.graphics.drawCircle(0, 0, 10);
_handle.graphics.endFill();
_handle.buttonMode = true;
_handle.x = Math.cos(topAngle)*_radius;
_handle.y = Math.sin(topAngle)*_radius;
_handleHolder.addChild(_handle);
_handle.addEventListener(MouseEvent.MOUSE_DOWN, onStartDrag);
}
private function onStartDrag(e : MouseEvent) : void
{
makeBox();
drawBox();
var rect : Rectangle = _box.getRect(_box);
_handle.startDrag(false, rect);
stage.addEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.addEventListener(MouseEvent.MOUSE_UP, onStopDrag);
}
private function onMouseMove(e : MouseEvent) : void
{
e.updateAfterEvent();
var rect : Rectangle = _box.getRect(_box);
var dist : Number = rect.height;
var per : Number = (_handle.y + dist/2)/dist;
var a : Number = _startAngle - _angleRange;
var b : Number = _startAngle + _angleRange;
var r : Number = b-a;
var targetAngle :Number = a + r*per;
targetAngle = targetAngle / 180 * Math.PI;
_handle.x = Math.sin(targetAngle)*_radius + 2;
}
private function onStopDrag(e : MouseEvent) : void
{
removeBox();
_handle.stopDrag();
_handle.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
stage.removeEventListener(MouseEvent.MOUSE_UP, onStopDrag);
stage.removeEventListener(MouseEvent.MOUSE_MOVE, onMouseMove);
}
private function removeBox() : void
{
_box.graphics.clear();
removeChild(_box);
}
private function drawBox() : void
{
_box.graphics.lineStyle(1,0xffffff, 0);
_box.graphics.moveTo(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius);
_box.graphics.lineTo(_radius, Math.sin(topAngle)*_radius);
_box.graphics.lineTo(_radius, Math.sin(bottmAngle)*_radius);
_box.graphics.lineTo(Math.cos(topAngle)*_radius, Math.sin(bottmAngle)*_radius);
_box.graphics.lineTo(Math.cos(bottmAngle) * _radius, Math.sin(topAngle)*_radius);
}
private function makeBox() : void
{
_box = new Sprite();
_box.x = stage.stageWidth/2;
_box.y = stage.stageHeight/2;
_box.mouseEnabled = false;
_box.mouseChildren = false;
addChild(_box);
}
private function calcAngles() : void
{
topAngle = _startAngle - _angleRange - 90;
topAngle = topAngle / 180 * Math.PI;
bottmAngle = _startAngle + _angleRange - 90;
bottmAngle = bottmAngle / 180 * Math.PI;
}
private function drawSegments() : void
{
_angleShape.graphics.lineStyle(2, 0x0000ff);
// FROM THE ALGORYTHMIST -- http://algorithmist.wordpress.com/2009/12/01/drawing-circular-segments-in-actionscript/
// now that start and end angle are fixed, draw a set of quads no more than PI/4 in arc at once
var angleDelta:Number = bottmAngle - topAngle;
var numSeg:Number = Math.ceil(angleDelta*4.0/Math.PI);
var arc:Number = angleDelta/numSeg;
// p is the vector from the origin of the wedge to (p0X,p0Y)
// q is the vector from the origin of the wedge to (p2X,p2Y)
// the vector p+q bisects the angle between p and q. The middle interpolation point is
// 'radius' units along that bisector.
var pX:Number = _radius*Math.cos(topAngle);
var pY:Number = _radius*Math.sin(topAngle);
var p0X:Number = pX;
var p0Y:Number = pY;
var qX:Number = 0;
var qY:Number = 0;
var angle:Number = topAngle;
// initial point at startAngle
var startX:Number = _radius*Math.cos(topAngle);
var startY:Number = _radius*Math.sin(topAngle);
_angleShape.graphics.moveTo( startX, startY );
var radInv:Number = 1.0/_radius;
// approximate each arc with a quad. Bezier
for( var i:uint=0; i<numSeg; ++i )
{
angle += arc;
qX = _radius*Math.cos(angle);
qY = _radius*Math.sin(angle);
var p2X:Number = qX;
var p2Y:Number = qY;
// unit vector in direction of bisector - alternative approach is two more trig. calcs to compute the coordinates.
// let's have some fun and do it a different way.
var dX:Number = (pX+qX)*radInv;
var dY:Number = (pY+qY)*radInv;
var d:Number = Math.sqrt(dX*dX + dY*dY);
dX /= d;
dY /= d;
// middle interpolation point is a distance of 'radius' units along direction of bisecting unit vector
var p1X:Number = _radius*dX;
var p1Y:Number = _radius*dY;
// compute control point so that quad. Bezier passes through (p0X,p0Y), (p1X,p1Y), and (p2X,p2Y) at t=0.5
var cX:Number = 2.0*p1X - 0.5*(p0X + p2X);
var cY:Number = 2.0*p1Y - 0.5*(p0Y + p2Y);
// You can compute the control point directly with nothing but sin & cos, but if memory serves it takes
// four more trig comps. for a total of six per loop iteration.
_angleShape.graphics.curveTo(cX, cY, p2X, p2Y);
// end point is start point for next iteration
p0X = p2X;
p0Y = p2Y;
pX = qX;
pY = qY;
}
}
private function initAngle() : void
{
_angleShape = new Sprite();
_angleShape.x = stage.stageWidth/2;
_angleShape.y = stage.stageHeight/2;
addChild(_angleShape);
}
private function drawAngle() : void
{
_angleShape.graphics.lineStyle(2, 0xff0000);
_angleShape.graphics.lineTo(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius);
_angleShape.graphics.lineStyle(2, 0x00ff00);
_angleShape.graphics.lineTo(Math.cos(bottmAngle)*_radius, Math.sin(bottmAngle)*_radius);
_angleShape.graphics.lineStyle(2, 0xff0000);
_angleShape.graphics.lineTo(0, 0);
}
private function drawCircle() : void
{
_circ = new Sprite();
_circ.graphics.lineStyle(1,0xffffff);
_circ.graphics.drawCircle(0, 0, _radius);
_circ.graphics.endFill();
_circ.x = stage.stageWidth/2;
_circ.y = stage.stageHeight/2;
// TO MASK OUT THE CIRCLE, YOU CAN USE THIS:
/*_mask = new Sprite();
_mask.x = stage.stageWidth/2;
_mask.y = stage.stageHeight/2;
_mask.mouseEnabled = false;
_mask.mouseChildren = false;
addChild(_mask);
_mask.graphics.beginFill(0xff0000, 1);
_mask.graphics.drawRect(Math.cos(topAngle)*_radius, Math.sin(topAngle)*_radius, _radius-Math.cos(topAngle)*_radius + 1, _radius/2-Math.sin(topAngle)*_radius);
*
*/
_circ.mask = _mask;
addChild(_circ);
}
}
}
Posted: January 7th, 2010 | Author: admin | Filed under: Uncategorized | No Comments »
So, like I said in my last post, I’m going to dedicate these few next posts to go over some of the techniques I used to create Flurrious.com.
The first thing I want to go over is the creation of the drawing application. The architecture of it is pretty simple, but crucial to making it work well, and having it be extendable and modular. My first step was to create the canvas. since a snowflake has an ice crystal formation, it has to have 6 sides. So my first step is to draw 6 triangles that form a hexagon:

The code for this is pretty simple, looks like this:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
/**
* @author iasseo
*/
public class SnowFlake extends MovieClip
{
private const SLICES : Number = 6;
private const RADIUS : Number = 300;
private var _sliceArray : Array = new Array();
private var _angle : Number;
public function SnowFlake()
{
_angle = Math.PI / SLICES;
createFlakeStage();
}
private function createFlakeStage() : void
{
for (var n : Number = 0;n < SLICES; n++)
{
var slice : Sprite = createSlice(_angle);
slice.x = stage.stageWidth / 2;
slice.y = stage.stageHeight / 2;
slice.rotation = 360 / SLICES * n;
_sliceArray.push(slice);
addChild(slice);
}
}
private function createSlice(angle : Number) : Sprite
{
var slice : Sprite = new Sprite();
slice.graphics.moveTo(0, 0);
slice.graphics.lineStyle(1,0);
slice.graphics.beginFill(0,.1);
slice.graphics.lineTo(Math.cos((angle)-Math.PI/2)*RADIUS, Math.sin((angle)-Math.PI/2)*RADIUS);
slice.graphics.lineTo(Math.cos(-(angle)-Math.PI/2)*RADIUS, Math.sin(-(angle)-Math.PI/2)*RADIUS);
slice.graphics.lineTo(0, 0);
slice.graphics.endFill();
slice.graphics.moveTo(0, 0);
slice.graphics.lineTo(0,Math.sin((_angle)-Math.PI/2)*RADIUS);
slice.graphics.endFill();
return slice;
}
}
}
Now, even though this is my canvas which I’m using to capture the mouse events, I’m going to draw the actual shapes on a separate Sprite, so I can have better control. In order to do that, I’m going to place 6 empty Sprites in the center of the hexagon, each one rotated, just like the triangles I drew. I’ll add a new function – createShapeHolders() – to the constructor (notice that I’m disabling all MouseEvents for these ’shapes’, because I want to control them from the canvas I drew earlier). For each of the triangles (which are separate Sprites), I’m going to add a MouseEvent, which will trigger the drawing application. I’m going to add that to the ‘for loop’ in the createFlakeStage() function, and I’m also adding 3 MouseEvent functions: beginShape, renderShape and endShape.
When I click on any of the triangles now, beginShape() will save the slice I clicked on as _slice (added as a private var to the class), and trigger a MOUSE_MOVE event. Then, as I move the mouse, the renderShape() function will draw on all 6 sides of the hexagon:

CLICK TO SEE THIS IN ACTION
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* @author iasseo
*/
public class SnowFlake extends MovieClip
{
private const SLICES : Number = 6;
private const RADIUS : Number = 300;
private var _sliceArray : Array = new Array();
private var _angle : Number;
private var _shapeHolders : Vector.<Sprite> = new Vector.<Sprite>();
private var _slice : Sprite;
public function SnowFlake()
{
_angle = Math.PI / SLICES;
createFlakeStage();
createShapeHolders();
}
private function createShapeHolders() : void
{
for (var n : Number = 0;n < SLICES; n++)
{
var shape : Sprite = new Sprite();
shape.mouseEnabled = false;
shape.mouseChildren = false;
shape.x = stage.stageWidth / 2;
shape.y = stage.stageHeight / 2;
_shapeHolders.push(shape);
shape.rotation = 360 / SLICES * n;
addChild(shape);
}
}
private function createFlakeStage() : void
{
for (var n : Number = 0;n < SLICES; n++)
{
var slice : Sprite = createSlice(_angle);
slice.x = stage.stageWidth / 2;
slice.y = stage.stageHeight / 2;
slice.rotation = 360 / SLICES * n;
slice.addEventListener(MouseEvent.MOUSE_DOWN, beginShape);
slice.alpha = 1;
_sliceArray.push(slice);
addChild(slice);
}
}
private function createSlice(angle : Number) : Sprite
{
var slice : Sprite = new Sprite();
slice.graphics.moveTo(0, 0);
slice.graphics.lineStyle(1,0);
slice.graphics.beginFill(0,.1);
slice.graphics.lineTo(Math.cos((angle)-Math.PI/2)*RADIUS, Math.sin((angle)-Math.PI/2)*RADIUS);
slice.graphics.lineTo(Math.cos(-(angle)-Math.PI/2)*RADIUS, Math.sin(-(angle)-Math.PI/2)*RADIUS);
slice.graphics.lineTo(0, 0);
slice.graphics.endFill();
slice.graphics.moveTo(0, 0);
slice.graphics.lineTo(0,Math.sin((_angle)-Math.PI/2)*RADIUS);
slice.graphics.endFill();
return slice;
}
private function beginShape(e : MouseEvent) : void
{
_slice = e.target as Sprite;
for (var i : Number = 0;i < SLICES; i++)
{
_shapeHolders[i].graphics.lineStyle(1,0xFFFFFF);
_shapeHolders[i].graphics.moveTo(_slice.mouseX, _slice.mouseY);
}
stage.addEventListener(MouseEvent.MOUSE_MOVE, renderShape);
stage.addEventListener(MouseEvent.MOUSE_UP, endShape);
}
private function renderShape(e : MouseEvent) : void
{
for (var i : Number = 0;i < SLICES; i++)
{
_shapeHolders[i].graphics.lineTo(_slice.mouseX, _slice.mouseY);
}
}
private function endShape(e : MouseEvent) : void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, renderShape);
stage.removeEventListener(MouseEvent.MOUSE_UP, endShape);
}
}
}
Now the only problem is that it doesn’t look like a symmetrical drawing… it basically copies the shape you’re drawing and places it in a circle. Now we need to add a reflection to the shape. So, to do that, we’ll have to add 2 Sprites to each of the ’shapes’ we created in the createShapeHolders() function. One of those shapes we’ll flip horizontally (scaleX = -1) and then, each time we trigger beginShape and renderShape, we’ll use the FP10 copyFrom() function to create a reflection effect. All we have left to do now is to hide the canvases, and start drawing! here is the result:

CLICK HERE TO SEE IT IN ACTION – CLICK AND DRAG NEAR THE CENTER OF THE STAGE
and here is the final code:
package
{
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
* @author iasseo
*/
public class SnowFlake extends MovieClip
{
private const SLICES : Number = 6;
private const RADIUS : Number = 300;
private var _sliceArray : Array = new Array();
private var _angle : Number;
private var _shapeHolders : Vector.<Sprite> = new Vector.<Sprite>();
private var _slice : Sprite;
public function SnowFlake()
{
_angle = Math.PI / SLICES;
createFlakeStage();
createShapeHolders();
}
private function createShapeHolders() : void
{
for (var n : Number = 0;n < SLICES; n++)
{
var shape : Sprite = new Sprite();
shape.mouseEnabled = false;
shape.mouseChildren = false;
shape.addChild(new Sprite());
shape.addChild(new Sprite());
shape.getChildAt(1).scaleX = -1;
shape.x = stage.stageWidth / 2;
shape.y = stage.stageHeight / 2;
_shapeHolders.push(shape);
shape.rotation = 360 / SLICES * n;
addChild(shape);
}
}
private function createFlakeStage() : void
{
for (var n : Number = 0;n < SLICES; n++)
{
var slice : Sprite = createSlice(_angle);
slice.x = stage.stageWidth / 2;
slice.y = stage.stageHeight / 2;
slice.rotation = 360 / SLICES * n;
slice.addEventListener(MouseEvent.MOUSE_DOWN, beginShape);
slice.alpha = 0;
_sliceArray.push(slice);
addChild(slice);
}
}
private function createSlice(angle : Number) : Sprite
{
var slice : Sprite = new Sprite();
slice.graphics.moveTo(0, 0);
slice.graphics.lineStyle(1,0);
slice.graphics.beginFill(0,.1);
slice.graphics.lineTo(Math.cos((angle)-Math.PI/2)*RADIUS, Math.sin((angle)-Math.PI/2)*RADIUS);
slice.graphics.lineTo(Math.cos(-(angle)-Math.PI/2)*RADIUS, Math.sin(-(angle)-Math.PI/2)*RADIUS);
slice.graphics.lineTo(0, 0);
slice.graphics.endFill();
slice.graphics.moveTo(0, 0);
slice.graphics.lineTo(0,Math.sin((_angle)-Math.PI/2)*RADIUS);
slice.graphics.endFill();
return slice;
}
private function beginShape(e : MouseEvent) : void
{
_slice = e.target as Sprite;
for (var i : Number = 0;i < SLICES; i++)
{
var side1 : Sprite = _shapeHolders[i].getChildAt(0) as Sprite;
var side2 : Sprite = _shapeHolders[i].getChildAt(1) as Sprite;
side1.graphics.lineStyle(1,0xFFFFFF);
side1.graphics.moveTo(_slice.mouseX, _slice.mouseY);
side2.graphics.copyFrom(side1.graphics);
}
stage.addEventListener(MouseEvent.MOUSE_MOVE, renderShape);
stage.addEventListener(MouseEvent.MOUSE_UP, endShape);
}
private function renderShape(e : MouseEvent) : void
{
for (var i : Number = 0;i < SLICES; i++)
{
var side1 : Sprite = _shapeHolders[i].getChildAt(0) as Sprite;
var side2 : Sprite = _shapeHolders[i].getChildAt(1) as Sprite;
side1.graphics.lineTo(_slice.mouseX, _slice.mouseY);
side2.graphics.copyFrom(side1.graphics);
}
}
private function endShape(e : MouseEvent) : void
{
stage.removeEventListener(MouseEvent.MOUSE_MOVE, renderShape);
stage.removeEventListener(MouseEvent.MOUSE_UP, endShape);
}
}
}
Posted: January 6th, 2010 | Author: admin | Filed under: Uncategorized | No Comments »
I haven’t posted anything is the past few weeks because I was busy working on Flurrious.com — Digitas’ ‘09 holiday card. It let’s you draw a snowflake and send it to a friend — and watch all of the other snowflakes other people make. For each snowflake sent, Digitas donates $1 to UNICEF.
The site has done MUCH better than expected — over 23,000 snowflakes were made (in less than 2 weeks), and almost $7,000 donated to UNICEF. The site is pretty small at 200kb, but so far we’ve served over 600GB of data to users (most of it is probably the snowflakes that are being saved as PNGs on the server).

To create this application I had to do an extensive brush-up on my flash drawing API skills. I’m using some of the new features from FP10 like IGraphicsPath and the 3D rotations (as well as Papervision3D). That graphics data is being saved in Vector arrays, and is stored on the database. When you view a snowflake, that data is being passed back to flash, and then get’s drawn again with the same API.
In the next few posts I’ll talk about some of the techniques I used to create the application. some of the highlights in my opinion are: saving and recreating vector data, creating smooth lines, and creating the circular slidres. Creating the snowflake generative drawing I think was the least challenging thing in the site…
-itai
Posted: November 16th, 2009 | Author: admin | Filed under: papervision3D | No Comments »
I was working on an Augmented Reality bit this weekend which involved a looping video. Normally this is a harmless operation which involves a simple onStreamStatus event, that by passing a “NetStream.Play.Stop” triggers a _netStream.seek(0); function. But when I tried that in PV3d the video would not loop… it was pretty frustrating, but eventually I figured out that the VideoStreamMaterial class in the Papervision3D package stopped rendering upon a “NetStream.Play.Stop” event, but didn’t resume it on a “NetStream.Seek.Notify” event, which I had to manually add.
this is how the function looks like after the change:
private function onStreamStatus ( event:NetStatusEvent ):void
{
switch ( event.info.code )
{
case "NetStream.Play.Start":
animated = true;
break;
case "NetStream.Unpause.Notify":
animated = true;
break;
case "NetStream.Seek.Notify":
animated = true;
break;
case "NetStream.Play.Failed":
animated = false;
break;
case "NetStream.Play.Stop":
animated = false;
break;
case "NetStream.Play.StreamNotFound":
animated = false;
break;
case "NetStream.Pause.Notify":
animated = false;
break;
}
}
Posted: November 10th, 2009 | Author: admin | Filed under: Effects | No Comments »
I’m continuing my efforts to create an easy-to-use effect library. For now I’m concentrating on 2D matrix effects — the previous one was halfTone. This one is a devision of an image (or any displayObjects for that matter) into smaller segments.
here’s what it looks like (click to watch animation):

here is the code involved with using the effect:
devide = new Devide(_loadedBitmap, 12, 0x000000);
addChild(devide);
devide.swipeLeftToRight = 0;
seq = new TimelineLite({onComplete:restartTween});
seq.append(TweenLite.to(devide, 1, {swipeLeftToRight:1}));
seq.append(new TweenLite(devide, 1, {swipeRightToLeft:0}));
seq.append(new TweenLite(devide, 1, {swipeTopToBottom:1}));
seq.append(new TweenLite(devide, 1, {swipeBottomToTop:0}));
It is based on my previous work that I posted here.
Posted: November 5th, 2009 | Author: admin | Filed under: Effects | No Comments »
I started working on an effect library with an easy-to-use API which will be easily attached to any tweening engine. I’m still working hard on the API and on how the whole thing is architectured, so I’m not going to include source code this time, but to give you a glimpse of how this is going to look, here’s an example of the Halftone effect which is going to be part of the Matrix2D package (it will include stuff like pixelate and explode effects).
the following effect is achieved simply by typing the following:
halfTone = new HalfTone(_loadedBitmap, 16);
addChild(halfTone);
but the fun part is animating the effect with a simple API. I’m using the new TweenLite v11, but any tween engine or really any other way (like controlling the swipe with the position of the mouse). here’s how I’m creating the different swipes in the example below:
halfTone.swipeLeftToRight = 0;
seq = new TimelineLite({onComplete:restartTween});
seq.append(new TweenLite(halfTone, 1, {swipeLeftToRight:1}));
seq.append(new TweenLite(halfTone, 1, {swipeRightToLeft:0}));
seq.append(new TweenLite(halfTone, 1, {swipeTopToBottom:1}),1);
seq.append(new TweenLite(halfTone, 1, {swipeBottomToTop:0}));
seq.append(new TweenLite(halfTone, 1, {swipeTLtoBR:1}),1);
seq.append(new TweenLite(halfTone, 1, {swipeTLtoBR:0}));

Special thanks to Joe Ferrari for helping me through the diagonal array math (still working on the BottomLeft to TopRight swipe)
Posted: October 31st, 2009 | Author: admin | Filed under: Uncategorized | No Comments »
after some thought of how to make this more practical, I decided to make another version.
In this version the 2 boxes next to the selected box and the 2 above and below grow as well, and the response and alignment is much better.
here’s what it looks like now:

here is the source
Posted: October 28th, 2009 | Author: admin | Filed under: Effects, tips and tricks | 1 Comment »
I had a couple of people ask me in the past couple of weeks about dynamic positioning of elements on a page, which change their position when other elements change size. Kind of like the ADIDAS WEBSITE effect.
The thing that is hard to get I think is a natural dynamic movement, and will be very apparent if you are doing this in an event-driven way. So I decided to do a quick example of how this would look like using a 2D matrix and using an EnterFrame event to detect the position of each element in the grid.
you can check out the result below:

basically, the way I set it up is to devide the grid into rows — each row has a Sprite that holds all of the elements in that row. On each frame, each one of the boxes checks the X and WIDTH of the box before it and changes it’s X position accordingly, and each Sprite Holder checks the Y and HEIGHT position of the row before it and calculates it’s position accordingly.
next I’ll try to use some collision detection and get a better real-world feel to it.
as always – here’s the SOURCE
Posted: October 28th, 2009 | Author: admin | Filed under: Effects, PixelBender | 1 Comment »
After playing around a bit with the Sprite approach to crate halfTone, I realized I don’t have enough computing power to go fullscreen with it, so I turned to PixelBender. it’s a bit different working in PB, and a bit confusing, but with a little fiddling around I created a halftone filter (I couldn’t find any to download — the one on the PB Exchange doesn’t have the PBK file, so there’s no way to know the paramaters that you can control…). I ended up making these paramaters to work with:
brightness (the color f the dots from black [0.0] to white [1.0])
multiplier (offsets the size of the dots)
offset (distance between dots)
radius (ummm, the radius of the dots)
I realized that in order to smoothly fade it it is better to draw the bitmap with the PB effect onto another bitmap, effectively flattening the effect (for a halfTone there really isn’t any advantage of playing with the parameters in real time), and then disposing of the original BMP and the filter, freeing up much needed power.
here is a sample of what it looks like:

you can download the source here.
and here is the source of the PBK.
Posted: October 26th, 2009 | Author: admin | Filed under: Effects | No Comments »
I had to do some halftone experiments for a project, and so I looked around for some code. There were a few examples out there but I didn’t find anything that I really liked so I decided to create one on my own.
The basic principle I went with was to create dots, and according to the brightness level of the pixel I was sampling, I would scale the dot down (full brightness = scale:0, no brightness = scale:1).
Here’s what I came up with. you can download the source here.

I used BetweenAS3 for the transitions.
-i