Flickr Uploadr = theGOOD Uploadr

I’ve been busy lately over at theGOOD

Media_httpfarm3static_sehlp

What it is

theGOOD Uploadr is a desktop application built on Adobe Air. The application is currently in alpha with a push to release beta around the first of the year 2010.

theGOOD Uploadr aims to improve and augment the Flickr experience by adding many features to the uploading process.

Some Links

theGOOD Uploadr
follow along for updates.
theGOOD Uploadr in the Flickr App Garden.
theGOOD Uploadr is a product of theGOOD. An interactive think tank.

Google Docs + Yahoo Pipes = CMS

So, you’ve got a client that wants to manage their website content. They want to be able to update every field on their Flash website, er I mean “experience”. But there’s a catch… they FEAR technology and complex interfaces. They feel that WordPress is too complex, never mind a proprietary custom build CMS.

What’s a developer to do?

THIS:

1. Create a Google Docs Spreadsheet – For this example I’m using row 1 to hold the field vars.

Media_httpwwwchristes_iugsb

2. Set it to publish as a webpage – Be sure to select CSV format. Be sure to set it to re-publish when any editing occurs.

Media_httpwwwchristes_racnp

3. Set up Yahoo Pipes to fetch the CSV data – Set appropriate data mapping, renaming and use Regex to ensure data is proper.

Media_httpwwwchristes_hrxme

4. Publish Pipe as your favorite data feed – For this example I chose JSON.

Media_httpwwwchristes_cqbkc

5. Load JSON into your Flash app. BOOM!

Bladow, your client can now go on doing what they’ve always done — edit an excel doc ( Google Doc ). They make changes there, it changes on their fancy experiential website.

Genius.

WordPress Flash Navigation

Consider this beta, and not heavily tested. Just wanted to get it out there while I’m still working on it.

For a recent project a client wanted more control over the display of their WordPress navigation. They wanted to be able to use any font. They also wanted a dynamic fold-able navigation that enables access to all categories without re-loading the page. This was a perfect project for me since I use WordPress all over the mofo place. For example, you can see the navigation in use over there to the right. Also, as I’ve stated previously, I’m a big fan of leveraging the many publishing outlets I already use. So, I buit the nav in Flash connecting to WordPress via XMLRPC using some classes from http://mattism.com/. This essentially allows me to use WordPress as a content management system for Flash. You could obviously see how this could be applied to entire sites, like I have with my homepage. I’ve thought about building this a WordPress plugin, and maybe down the road I will, but I doubt it as I’ll probably jump ship and start another project per usual. Besides, everyone knows you can’t make money writing WordPress plugins.

How It Works:
Flash calls _rpc.call(“wp.getCategories”) to xmlrpc.php which returns an array of categories. I use this array to create a bunch of MovieClip()s. These clips add TextFields as children, are sorted and have events applied to them that enable the interactions. Two fonts reside in the library. One for the top node and one for the child and grandchildren nodes.

Features [the current goods]:

  • Dynamic – Works dynamically with WordPress categories. You update your categories in WordPress, they show properly in Flash
  • Sorting – Dynamically sorts top nodes. Controlled by WordPress plugin my category order. For this to work I had to make a small addition to the WordPress xmlrpc.php, located in your WordPress root folder, to return the category term order. Added line 2776 – $struct['order'] = $cat->term_order;
  • Page recognition – Recognizes the page you’re on and dynamically opens navigation to the parent node of said page onload. I could have used XMLRPC tomake this call, I’m sure. However, I opted to pass in the page url via Flashvars and run a check to find a match. When a match is found the nav opens to it’s parent node.
  • Folding – Uses Grant Skinner GTween for interactions.
  • Multiple – Allows posts to live under multiple category nodes.

Wish List [the future goods]:

  • Multiline – Currently only supports single line category titles, so you’re limited in char length
  • Scrolling – Currently the length of your category list is limited to the length of the swf. I plan to add functions to enable scrolling of the list based on mouseY. This will free up the nav to be as long as you desire.
  • Post count – Do people really use this though? Probably not as its annoying.
  • Levels – Currently the nav only supports 3 levels. It would be nice to be infinite.
  • Build in the rest of WordPress feature support for tag cloud, recent comments etc.

Total devel time: 2 days, or about 12 hours.

I’d love to see where other people take the code and what people build with it.

Source Code:
wpNavMain.as

/**
* wpNavMain by Chris Teso. Mar 19, 2009
* Visit www.christeso.com/blog for documentation, updates and more free code.
*
*
* Copyright (c) 2009 Chris Teso
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
**/
package
{
        import flash.display.*;

        public class wpNavMain extends Sprite
        {

                /*
                ========================================================
                | Constructor
                ========================================================
                */

                public function wpNavMain ()
                {
                        stage.align = StageAlign.TOP_LEFT;

                        // add nav
                        var wp:Wp = new Wp()
                        addChild( wp )
                }
        }
}

Wp.as

/**
* Wp by Chris Teso. Mar 19, 2009
* Visit www.christeso.com/blog for documentation, updates and more free code.
*
*
* Copyright (c) 2009 Chris Teso
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
* files (the "Software"), to deal in the Software without
* restriction, including without limitation the rights to use,
* copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
**/

package
{
        import com.gskinner.motion.*
        import com.mattism.http.xmlrpc.*;
        import com.mattism.http.xmlrpc.util.*;
        import flash.filters.*;
        import flash.media.*;
        import flash.ui.*;
        import flash.display.*;
        import flash.events.*;
        import flash.net.*;
        import flash.utils.*;
        import flash.geom.*;
        import flash.text.*;
        import fl.transitions.*;
        import fl.transitions.easing.*;
        import flash.system.SecurityPanel;
        import flash.system.Security;

        public class Wp extends Sprite
        {

                /*
                ========================================================
                | Private Variables                         | Data Type
                ========================================================
                */
                private var _navArray:Array = new Array();
                private var _rpc:Connection;
                private var _topFont:Font = new topFont();
                private var _roadSign:Font = new roadSign();
                private var _topFmt:TextFormat = new TextFormat()
                private var _currUrl:String = ""
                private var _hideTimer:Timer

                private var _textYPad:int = 16
                private var _navSpeed:Number = .2
                /*
                ========================================================
                | Constructor
                ========================================================
                */

                public function Wp ()
                {
                        loadRpc()
                }

                private function checkPage()
                {
                        // load in title
                        var paramList:Object = this.root.loaderInfo.parameters;

                        // set var to hold text
                        var _currUrl:String = paramList["url"]

                        //_currUrl = "http://www.christeso.com/index.php/category/portfolio/truth/truth-found/"

                        // scan through array and open nav to that one
                        for( var i=0;i MovieClip(mc.parent).origY )
                                        {
                                                yLeap = _navArray[i].mc.origY + ( _totOpen*_textYPad )
                                                new GTween( _navArray[i].mc, _navSpeed, {y:yLeap} )
                                        }
                                        else
                                        {
                                                yLeap = _navArray[i].mc.origY
                                                new GTween( _navArray[i].mc, _navSpeed, {y:yLeap} )
                                        }
                                }

                                // push down child nodes as long as they are below the node you're on and are a child of the node you're on
                                if( _navArray[i].childMc != null )
                                {
                                        if( _navArray[i].childMc.parent == mc.parent )
                                        {
                                                if( _navArray[i].childMc.origY > mc.origY )
                                                {
                                                        yLeap = _navArray[i].childMc.origY + ( _totOpen*_textYPad )
                                                        new GTween( _navArray[i].childMc, _navSpeed, {y:yLeap} )
                                                }
                                                else
                                                {
                                                        yLeap = _navArray[i].childMc.origY
                                                        new GTween( _navArray[i].childMc, _navSpeed, {y:yLeap} )
                                                }
                                        }
                                }

                                // make grandchildren visible
                                if( _navArray[i].grandChildMc != null )
                                {
                                        if( _navArray[i].grandChildMc.parent == mc )
                                        {
                                                _navArray[i].grandChildMc.visible = true
                                                new GTween( _navArray[i].grandChildMc, _navSpeed, {alpha:1} )
                                        }
                                        else
                                        {
                                                new GTween( _navArray[i].grandChildMc, _navSpeed/2, {alpha:0, autoHide:true} )
                                        }
                                }
                        }
                }

                private function hideGrandChildren( e:Event )
                {
                        // amount to go down
                        var yLeap:Number;                        

                        // ok we can prob do this in one big loop
                        for( var i=0;i

Download CS4 AS3 FLA and Classes

Enjoy.

Portland Photographer – Chris Teso

Media_httpwwwchristes_hfkyb

Over the last couple of years my addiction to taking pictures every day has grown in intensity. More recently this addiction has heightened my curiosity to a point of seriousity. You do realize that seriousity should have inclusion confirmation from Merriam-Webster. If truthiness can make in, seriousity should. Seriously. Ok, back to the point. I’m getting more serious about photography. I even purchased a serious camera. Along with this serious camera, and an overabundance of seriousity about it’s use, I’ve gone and constructed myself a website dedicated to my photography. It is my hope that this will inspire and urge potential clients to contact me about my services.

The concept of the site is to take as much distraction out of the interface as possible to allow all focus on the content, the photography. I decided the entire site could be controlled by a small non intrusive control. I also wanted users to be able to interact with the photography by zoom and panning. Users also have the option to zoom out to see the full photo. Finally, I wanted a super easy way to content manage the site. Since I’m an avid Flickr user, its API was a natural CMS choice. I merely have to tag my photos in Flickr and they show up categorized on my site. I’m a big fan of leveraging the many publishing outlets I already use.

If you are a photographer, and are interested in owning a site similar to this one, chirp me.

Chris Teso – Portland Photographer

Music Visualization Engine and Generative Drawing

http://vimeo.com/moogaloop.swf?clip_id=3191128&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1
The Neural Orb from chris teso on Vimeo.

130 seconds of a music visualization engine and generative drawing built in AS3 using particles and physics engine.

See it in it’s 4:02 entirety HERE.

512 particles are released with instructions to randomly disperse throughout the scene. Variants include friction and wander. Particle location is constantly tracked and more particles are drawn at that location. These particles are sized and alpha’d according to stage location creating a “corridor”.

Music visualization occurs by looping through SoundMixer.computeSpectrum and creating a ByteArray. Each of the 512 particles are controlled the ByteArray which conveniently contains 512 bytes of data. Each byte contains a floating-point value. This value determines the individual particles scale and glow.

I hope to make this more interesting if/when I get some free time.

Music: All Mine | Portishead

Motion Detection and Typography

http://vimeo.com/moogaloop.swf?clip_id=2829875&server=vimeo.com&show_title=0&show_byline=0&show_portrait=0&color=00adef&fullscreen=1
Webcam Swarm – Motion Detection from chris teso on Vimeo.

Reactive installation concept idea for future interactive installation using motion detection.

Concept: Using Particles to conform to typography.

Picture this large. Now take that image and double it. That’s how I envision it. Giant.

Try it for yourself : Reactive Motion Detection and Typography [webcam es necessitous]

Permalink: http://www.christeso.com/index.php/lab/motion-detection-and-typography/

BIT-101 Particle class in AS3

/*Public Properties:


vx:Number – the velocity on the x axis. default is 0
vy:Number – the velocity on the y axis. default is 0
damp:Number – a pseudo-friction value. 1.0 is no friction. Usual values are between 0.9 and 1.0. default is 0.9
bounce:Number – how much the particle will bounce from a wall. -1.0 will bounce with same force it hit with.

default is -0.5

grav:Number – how much velocity is added to vy each frame. Usual values are 0.0 to 2.0. default is 0
maxSpeed:Number – maximum allowed speed in any direction for a particle.

default is Number.MAX_VALUE (essentially infinity or no limit)

wander:Number – gives particle a random motion. numbers between 0 and 5 works well. default is 0
draggable:Boolean – if true, drag and throw is possible on the particle
edgeBehavior:String – determines behavior when particle hits an edge of the world.

Can be set to "wrap", "bounce", or "remove"
        wrap causes the particle to disappear and appear on the opposite edge of the space
        bounce causes the particle to bounce off the edge at a speed determined by the bounce property
        remove causes the particle to be permanently deleted if it leaves the space.

turnToPath:Boolean – if true, particle will turn towards the direction it is moving in.

Public Methods:


setBounds(bounds:Object)

- sets the "walls" of the universe in which the particle will be able to travel
- arguments:
    bounds. an object containing properties: xMin, xMax, yMin, yMax.
            you can directly use the object returned from the method getBounds().
            default values are the Stage dimensions.

gravToMouse(bGrav:Boolean [, force:Number])

- causes the particle to gravitate towards the mouse. it is advised that us use maxSpeed along with this,
  as this method can create near infinite particle speeds.
- arguments:
    bGrav. if true, particle will gravitate towards mouse. if false, it won't. default is false.
    force. the gravitational force applied to the particle.
           generally high numbers of 1000 or more are used. default is 1000

springToMouse(bSpring:Boolean [, force:Number])

- causes the particle to spring to the mouse
- arguments:
    bSpring. if true, particle will spring to the mouse. if false, it won't. default is false.
    force. the strength of the spring. generally numbers less than 1 are used. default is 0.1

repelMouse(bRepel:Boolean [, force:Number, minDist:Number])

- causes the particle to spring away from the mouse
- arguments:
    bRepels. if true, particle will spring away from the mouse. if false it won't.
    force. the strength of the spring action. generally numbers less than 1 are used. default is 0.1
    minDist. the distance in pixels from the mouse that the particle will attempt maintain.
             default is 100
- returns:
    the index number of the point added (can be used to remove the point)

addSpringPoint(x:Number, y:Number [, force:Number])

- adds a stationary point to which the particle will spring. any number of points can be added,
  but the result will be that the particle will spring to an point which is the average of all points.
- arguments:
    x, y. the point to which the particle will spring.
    force. the strength of the spring. default is 0.1
- returns:
    the index number of the point added (can be used to remove the point)

addGravPoint(x:Number, y:Number [, force:Number])

- adds a stationary point to which the particle will try to gravitate. any number of points can be added.
- arguments:
    x, y. the point to which the particle will gravitate.
    force. the gravitational force of the point. default is 1000
- returns:
    the index number of the point added (can be used to remove the point)

addRepelPoint(x:Number, y:Number [, force:Number, minDist:Number])

- adds a stationary point which the particle will try to spring away from.
  any number of points can be added.
- arguments:
    x, y. the point the particle will try to avoid.
    force. the force of the spring. default is 0.1
    minDist. the distance in pixels from the point that the particle will try to maintain. default is 100
- returns:
    the index number of the point added (can be used to remove the point)

addSpringClip(clip:MovieClip [, force:Number])

- designates a movie clip to which the particle will spring towards. any number of clips can be added.
- arguments:
    clip. a movie clip towards which the particle will spring.
    force. the strength of the spring. default is 0.1
- returns:
    the index number of the clip added (can be used to remove the clip from the list)

addGravClip(clip:MovieClip [, force:Number])

- designates a movie clip to which the particle will gravitate. any number of clips can be added.
- arguments:
    clip. a movie clip towards which the particle will spring.
    force. the strength of the gravitation. default is 1000
- returns:
    the index number of the clip added (can be used to remove the clip from the list)

addRepelClip(clip:MovieClip [, force:Number, minDist:Number])

- designates a movie clip which the particle will spring away from. any number of clips can be added.
- arguments:
    clip. a movie clip which the particle will spring away from.
    force. the strength of the spring. default is 0.1
    minDist. the distance in pixels from the point that the particle will try to maintain. default is 100
- returns:
    the index number of the clip added (can be used to remove the clip from the list)

removeSpringPoints(index:Number)

- removes a previously specified spring point
- arguments:
    index. the number of the point to remove

removeGravPoints(index:Number)

- removes a previously specified gravity point
- arguments:
    index. the number of the point to remove

removeRepelPoints(index:Number)

- removes a previously specified repel point
- arguments:
    index. the number of the point to remove

clearSpringPoints()

- removes all spring points

clearGravPoints()

- removes all grav points

clearRepelPoints()

- removes all repel points

clearSpringClips()

- removes all spring points

clearGravClips()

- removes all grav points

clearRepelClips()

- removes all repel points*/

package
{

import flash.display.MovieClip;
import flash.events.*;

/**
 *      Original AS2 Class by Keith Peters (BIT-101)
 *      Conversion to AS3 by Chris Teso
 */
public class Particle extends MovieClip {

    private var __vx:Number                 = 0;
    private var __vy:Number                 = 0;
    private var __k:Number                  = .2;
    private var __damp:Number               = .9;
    private var __bounce:Number             = -.5;
    private var __grav:Number               = 0;
    private var __bounds:Object;
    private var __draggable:Boolean         = false;
    private var __edgeBehavior:String       = "bounce";
    private var __drag:Boolean;
    private var __oldx:Number;
    private var __oldy:Number;
    private var __maxSpeed:Number;
    private var __wander:Number             = 0;
    private var __turn:Boolean              = false;
    private var __springToMouse:Boolean     = false;
    private var __mouseK:Number             = .2;
    private var __gravToMouse:Boolean       = false;
    private var __gravMouseForce:Number     = 5000;
    private var __repelMouse:Boolean        = false;
    private var __repelMouseMinDist:Number  = 100;
    private var __repelMouseK:Number        = .2;
    private var __springPoints:Array;
    private var __gravPoints:Array;
    private var __repelPoints:Array;
    private var __springClips:Array;
    private var __gravClips:Array;
    private var __repelClips:Array;
    private var __efClip:MovieClip;

    //
    public function Particle()
    {
        trace( "particle initialized" )
        addEventListener( Event.ADDED_TO_STAGE, onAddedToStage );
        init();
    }

    private function onAddedToStage( event:Event ):void
    {
        removeEventListener( Event.ADDED_TO_STAGE, onAddedToStage );
        //can access the stage now.
        //trace( "added to stage" );
    } 

    private function init():void
    {
        __bounds = new Object();
        setBounds( 0, Main.stage.stageWidth, 0, Main.stage.stageHeight );
        __maxSpeed = Number.MAX_VALUE;
        __springPoints = new Array();
        __gravPoints = new Array();
        __repelPoints = new Array();
        __springClips = new Array();
        __gravClips = new Array();
        __repelClips = new Array();

        __efClip = new MovieClip();
        __efClip.addEventListener( Event.ENTER_FRAME, __efHandler );

    }
    public function set vx(nVx:Number):void
    {
        __vx = nVx;
    }

    public function get vx():Number
    {
        return __vx;
    }

    public function set vy(nVy:Number):void
    {
        __vy = nVy;
    }

    public function get vy():Number
    {
        return __vy;
    }

    public function set damp(nDamp:Number):void
    {
        __damp = nDamp;
    }

    public function get damp():Number
    {
        return __damp;
    }

    public function set bounce(nBounce:Number):void
    {
        __bounce = nBounce;
    }

    public function get bounce():Number
    {
        return __bounce;
    }

    public function set grav(nGrav:Number):void
    {
        __grav = nGrav;
    }

    public function get grav():Number
    {
        return __grav;
    }

    public function set maxSpeed( nMaxSpeed:Number )
    {
        __maxSpeed = nMaxSpeed;
    }

    public function get maxSpeed():Number
    {
        return __maxSpeed;
    }

    public function set wander( nWander:Number ):void
    {
        __wander = nWander;
    }

    public function get wander():Number
    {
        return __wander;
    }

    public function set edgeBehavior(sEdgeBehavior:String):void
    {
        __edgeBehavior = sEdgeBehavior;
    }

    public function get edgeBehavior():String
    {
        return __edgeBehavior;
    }

    public function setBounds( left, right, top, bot)
    {
        __bounds.top = top;
        __bounds.bottom = bot;
        __bounds.left = left;
        __bounds.right = right;
    }

    public function set draggable( bDrag:Boolean ):void
    {
        __draggable = true;
        if ( bDrag )
        {
            this.addEventListener( MouseEvent.CLICK, pressHandler );
            this.addEventListener( MouseEvent.MOUSE_UP, releaseHandler );
            stage.addEventListener( MouseEvent.MOUSE_UP, outsideHandler) ; // releaseOutside handler hack

        } else
        {
            this.removeEventListener( MouseEvent.CLICK, pressHandler );
            this.removeEventListener( MouseEvent.MOUSE_UP, releaseHandler );
            stage.removeEventListener( MouseEvent.MOUSE_UP, outsideHandler );
            __drag = false;
        }
    }

    private function pressHandler( e:MouseEvent ):void
    {
        this.startDrag();
        __drag = true;
    }

    private function releaseHandler( e:MouseEvent ):void
    {
        this.stopDrag();
        __drag = false;
    }

    private function outsideHandler( e:MouseEvent ):void
    {
        this.stopDrag();
        __drag = false;
    }

    public function get draggable():Boolean
    {
        return __draggable;
    }

    public function set turnToPath(bTurn:Boolean):void
    {
        __turn = bTurn;
    }

    public function get turnToPath():Boolean
    {
        return __turn;
    }

    private function __efHandler( e:Event ):void
    {
        __move();
    }

    private function __move():void
    {
        var dx;
        var dy;
        var distSQ;
        var dist;
        var force;
        var tx;
        var ty;
        var point;
        var clip;
        var k;
        var minDist;

        if ( __drag )
        {
            __vx = this.x - __oldx;
            __vy = this.y - __oldy;
            __oldx = this.x;
            __oldy = this.y;

        } else
        {
            if ( __springToMouse )
            {
                __vx += ( this.parent.mouseX - this.x ) * __mouseK;
                __vy += ( this.parent.mouseY - this.y ) * __mouseK;
            }

            if ( __gravToMouse )
            {
                trace( "this.x = "+this.x )
                trace( "this.parent.mouseX ="+this.parent.mouseX )
                dx = this.parent.mouseX - this.x;
                dy = this.parent.mouseY - this.y;

                distSQ = dx * dx + dy * dy;
                dist = Math.sqrt( distSQ );
                force = __gravMouseForce / distSQ;
                __vx += force * dx / dist;
                __vy += force * dy / dist;
            }

            if ( __repelMouse )
            {
                dx = this.parent.mouseX - this.x;
                dy = this.parent.mouseY - this.y;

                dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < __repelMouseMinDist)
                {
                    tx = this.parent.mouseX - __repelMouseMinDist * dx / dist;
                    ty = this.parent.mouseY - __repelMouseMinDist * dy / dist;
                    __vx += (tx - this.x) * __repelMouseK;
                    __vy += (ty - this.y) * __repelMouseK;
                }
            }

            for ( var sp:uint=0; sp < __springPoints.length; sp++ )
            {
                point = __springPoints[sp];
                __vx += (point.x - this.x) * point.k;
                __vy += (point.y - this.y) * point.k;
            }

            for ( var gp:uint = 0; gp < __gravPoints.length; gp++ )
            {
                point = __gravPoints[gp];

                dx = point.x - this.x;
                dy = point.y - this.y;

                distSQ = dx * dx + dy * dy;
                dist = Math.sqrt( distSQ );
                force = point.force / distSQ;
                __vx += force * dx / dist;
                __vy += force * dy / dist;
            }

            for ( var rp:uint = 0; rp < __repelPoints.length; rp++ )
            {
                point = __repelPoints[rp];
                dx = point.x - this.x;
                dy = point.y - this.y;

                dist = Math.sqrt( dx * dx + dy * dy );
                if (dist < point.minDist)
                {
                    tx = point.x - point.minDist * dx / dist;
                    ty = point.y - point.minDist * dy / dist;

                    __vx += (tx - this.x) * point.k;
                    __vy += (ty - this.y) * point.k;

                }
            }

            for ( var sc:uint = 0; sc < __springClips.length; sc++ )
            {
                clip = __springClips[sc].clip;
                k = __springClips[sc].k;
                __vx += (clip.x - this.x) * k;
                __vy += (clip.y - this.y) * k;

            }

            for ( var gc:uint = 0; gc < __gravClips.length; gc++ )
            {
                clip = __gravClips[gc].clip;
                dx = clip.x - this.x;
                dy = clip.y - this.y;

                distSQ = dx * dx + dy * dy;
                dist = Math.sqrt( distSQ );
                force = __gravClips[gc].force / distSQ;
                __vx += force * dx / dist;
                __vy += force * dy / dist;
            }

            for ( var rc:uint= 0; rc < __repelClips.length; rc++ )
            {
                clip = __repelClips[rc].clip;
                minDist = __repelClips[rc].minDist;
                k = __repelClips[rc].k;
                dx = clip.x - this.x;
                dy = clip.y - this.y;

                dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < minDist)
                {
                    tx = clip.x - minDist * dx / dist;
                    ty = clip.y - minDist * dy / dist;
                    __vx += (tx - this.x) * k;
                    __vy += (ty - this.y) * k;

                }
            }
            __vx += Math.random() * __wander - __wander / 2;
            __vy += Math.random() * __wander - __wander / 2;
            __vy += __grav;
            __vx *= damp;
            __vy *= damp;

            var speed = Math.sqrt(__vx * __vx + __vy * __vy);
            if (speed > __maxSpeed) {
                __vx = __maxSpeed * __vx / speed;
                __vy = __maxSpeed * __vy / speed;
            }
            if (__turn)
            {
                this.rotation = Math.atan2(__vy, __vx) * 180 / Math.PI;
            }

            this.x += __vx;
            this.y += __vy;

            if(__edgeBehavior == "wrap")
            {
                if ( this.x > __bounds.right + this.width/2 )
                {
                    this.x = __bounds.left - this.width/2;
                } else if ( this.x < __bounds.left - this.width/2)
                {
                    this.x = __bounds.right + this.width/2;
                }
                if( this.y > __bounds.bottom + this.height/2)
                {
                    this.y = __bounds.top - this.height/2;
                } else if (this.y < __bounds.top - this.height/2)
                {
                    this.y = __bounds.bottom + this.height/2;
                }

            } else if(__edgeBehavior == "bounce")
            {
                if ( this.x > __bounds.right - this.width/2)
                {
                    this.x = __bounds.right - this.width/2;
                    __vx *= __bounce;
                } else if (this.x < __bounds.left + this.width/2){
                    this.x = __bounds.left + this.width/2;
                    __vx *= __bounce
                }
                if( this.y > __bounds.bottom - this.height/2){
                    this.y = __bounds.bottom - this.height/2;
                    __vy *= __bounce
                } else if ( this.y < __bounds.top + this.height/2){
                    this.y = __bounds.top + this.height/2;
                    __vy *= __bounce;
                }

            } else if(__edgeBehavior == "remove")
            {
                if( this.x > __bounds.right + this.width/2 || this.x < __bounds.left - this.width/2 ||
                   this.y > __bounds.bottom + this.height/2 || this.y < __bounds.top - this.height/2){
                    removeChild( this );
                }
            }
            if( stage != null )
                stage.invalidate();
        }
    };

    public function gravToMouse( bGrav:Boolean, force:Number ):void
    {
        if (bGrav) {
            if (!force) {
                var force = 1000;
            }
            __gravMouseForce = force;
            __gravToMouse = true;
        }
        else {
            __gravToMouse = false;
        }
    }

    public function springToMouse( bSpring:Boolean, force:Number ):void
    {
        if (bSpring)
        {
            if (!force) {
                var force = .1;
            }
            __mouseK = force;
            __springToMouse = true;

        } else
        {
            __springToMouse = false;
        }
    }

    public function repelMouse( bRepel:Boolean, force:Number, minDist:Number ):void
    {
        if (bRepel)
        {
            if (!force)
            {
                var force = .1;
            }
            if (!minDist)
            {
                var minDist = 100;
            }
            __repelMouseK = force;
            __repelMouseMinDist = minDist;
            __repelMouse = true;

        } else
        {
            __repelMouse = false;
        }
    }

    public function addSpringPoint(x:Number, y:Number, force:Number):Number
    {
        if (!force)
        {
            var force = .1;
        }
        __springPoints.push( {x:x, y:y, k:force} );
        return __springPoints.length - 1;
    }

    public function addGravPoint(x:Number, y:Number, force:Number):Number
    {
        if (!force)
        {
            var force = 1000;
        }
        __gravPoints.push( {x:x, y:y, force:force} );
        return __gravPoints.length - 1;
    }

    public function addRepelPoint( x:Number, y:Number, force:Number, minDist:Number ):Number
    {
        if (!force) {
            var force = .1;
        }
        if (!minDist) {
            var minDist = 100;
        }
        __repelPoints.push({x:x, y:y, k:force, minDist:minDist});
        return __repelPoints.length - 1;
    }

    public function addSpringClip(clip:MovieClip, force:Number):Number
    {
        if (!force)
        {
            var force = .1;
        }
        __springClips.push( {clip:clip, k:force} );
        return __springClips.length - 1;
    }

    public function addGravClip(clip:MovieClip, force:Number):Number
    {
        if (!force)
        {
            var force = 1000;
        }
        __gravClips.push({clip:clip, force:force});
        return __gravClips.length - 1;
    }

    public function addRepelClip( clip:MovieClip, force:Number, minDist:Number ):Number
    {
        if ( !force )
        {
            var force = .1;
        }
        if ( !minDist )
        {
            var minDist = 100;
        }
        __repelClips.push( {clip:clip, k:force, minDist:minDist} );
        return __repelClips.length - 1;
    }

    public function removeSpringPoint( index:Number ):void
    {
        __springPoints.splice(index, 1);
    }

    public function removeGravPoint( index:Number ):void
    {
        __gravPoints.splice(index, 1);
    }

    public function removeRepelPoint( index:Number ):void {
        __repelPoints.splice(index, 1);
    }

    public function removeSpringClip(index:Number):void
    {
        __springClips.splice(index, 1);
    }

    public function removeGravClip(index:Number):void
    {
        __gravClips.splice(index, 1);
    }

    public function removeRepelClip(index:Number):void
    {
        __repelClips.splice(index, 1);
    }

    public function clearSpringPoints():void
    {
        __springPoints = new Array();
    }

    public function clearGravPoints():void
    {
        __gravPoints = new Array();
    }

    public function clearRepelPoints():void
    {
        __repelPoints = new Array();
    }

    public function clearSpringClips():void
    {
        __springClips = new Array();
    }

    public function clearGravClips():void
    {
        __gravClips = new Array();
    }

    public function clearRepelClips():void
    {
        __repelClips = new Array();
    }
}

}

AS3 Polar Coordinates and Radians

/flash/radians.swf

Many times I’ve set up interfaces where I need to place different objects equidistant around a central object. The solution to this problem is to first calculate the angle of each object by converting Radians to Degrees. This can be expressed by the following formula

Media_httpuploadwikim_idwbg

So, you simply need to loop through your collection of objects and assign each a different angle. After that you plug that angle into a new Polar Point.

for(var i=0;i

Here’s the complete source: radians.zip

package
{
        import flash.ui.*;
        import flash.display.*;
        import flash.events.*;
        import flash.geom.*;

        public class Main extends Sprite
        {

                /*
                ========================================================
                | Private Variables                         | Data Type
                ========================================================
                */

                private var array:Array = new Array()
                private var circumference:int;

                /*
                ========================================================
                | Constructor
                ========================================================
                */

                public function Main ()
                {
                        stage.align = StageAlign.TOP_LEFT;

                        // make some balls
                        addParticle( 100 )

                        menu.txtParticles.text = 'Particles: 100';

                        stage.addEventListener( Event.ENTER_FRAME, runParticle )

                        menu.slideCircumference.addEventListener( Event.CHANGE, changeCircumference );
                        menu.particles.addEventListener( Event.CHANGE, changeParticles );

                }

                private function addParticle( num )
                {
                        stage.removeEventListener( Event.ENTER_FRAME, runParticle )

                        var tot:Number = array.length

                        // kill mc's
                        for( var t=0;t

Permalink: http://www.christeso.com/index.php/lab/as3-polar-coordinates-and-radians

Snow – A Reactive Environment Installation

http://vimeo.com/moogaloop.swf?clip_id=2566287&server=vimeo.com&show_title=1&show_byline=0&show_portrait=1&color=ffffff&fullscreen=1
Snow – Interactive Installation from chris teso on Vimeo. Commercial produced North.

Project Client

City of Portland Downtown Marketing Initiative in conjunction with North.

Project Goal

Create an outdoor reactive environment in which passersby could interact, based on their location and movements, with artists interpretations of snowfall in Portland.

Project Strategy and Equipment

Display – Custom made acrylic panels lined with photosensitive film built and erected to exact dimensions of installation window
Projection – Rear projection with flipped signal using a 5200 lumen Sanyo PDG-DXT10L Projector
Video CaptureLogitech QuickCam® Vision Pro
CPU – Mac Pro Quad
Application – Flash AS3
Industrial Design – Two large tarps sewn together to create light blocking canopy. Lining to seal off windows and acrylic. A shitload of Velcro.

Project Synopsis

As part of a larger campaign to brand Downtown Portland North was charged with creating an outdoor reactive environment in which passersby could interact, based on their location and movements, with artists interpretations of snowfall in Portland. Three traditional artists were commissioned by The Portland Institute for Contemporary Art to create their interpretation of snowfall in downtown Portland. These pieces were then transformed for use with my motion detection and tracking application built entirely in actionscript. The application was built to display 3 different scenes with randomly generated snowfall. The three scenes were set to rotate on a time interval. The application used motion detection to make the falling snowfall react and animate based on the location of an individuals movement. The application also incorporated and automated snapshot function that took a photo every 10 minutes and posted it to a private flickr account. This function was implemented solely for remote monitoring, ensuring the application was up and running. After going to the installation location and taking careful measurement of everything from window frame to projector distance, the installation was built and staged at North. We built a ‘to scale’ model of the window in the back of the office. This was necessary for accurate calibration of projector, and optimization of motion detection and tracking code. The staging was an extremely helpful and necessary step in eliminating early stage bugs such as projector calibration and camera positioning. We quickly learned the maximum distance for a USB signal, the proper use of DVI vs. DHMI to projector and the challenges of doing motion detection in every possible light range from complete darkness to bright sunshine. After testing stage was complete we moved the entire rig over to the installation spot located at 6th and Alder in Downtown Portland. We went about setting up a canopy to block out all extraneous light leak. The interior of the installation space was two stories of extremely large windows. The canopy we chose was a homemade compilation of two tarps strung up to the surrounding walls with rope. Since there was very expensive equipment residing under the canopy, the fear lingered of canopy failure collapsing down, resulting in devastating loss. We next set out to install the panels into the window frame. Since they were pre-cut to exact dimensions these flowed right in smoothly with only small light leaks needed to be sealed. We then hooked up the projector, cpu, camera, monitor, and application and set to testing. Testing in a staging environment is one thing. However, most tests are rendered moot when on-site. I quickly learned that reactive environments are just that, entirely dependent on their environment and all the challenges that come along with it. The motion detection is to run 24/7 for six weeks during all weather, lighting situations, and process location accurately with varying levels of distractions. Since the installation is located on an extremely busy downtown street corner, distractions ranged from traffic movement, pedestrians, bikers, storefront lights and weather. For testing purposes I built many functions that allows the system to be calibrated without actually going into the code, but rather using an external UI to update blurring, light detection levels, contrast, and other variables. After several days of calibration, code tweaks and testing the application has been running uninterrupted and has gained quality exposure for Downtown Portland. Many fine citizens of Portland have had a unique interactive experience, and have consequently spread kind words about the project. Furthermore, the project is a successful case study on the implementation of new technology and reactive medium into a larger branding campaign.

Project Challenges

Development – Create a motion detection application that worked in every possible light and weather condition.
Design – Making traditional raster art work work in a complex location detection application and animation.
Industrial Design – Create an environment that optimized presentation and functionality in varying environmental variables.

More information on the design and development process

Permalink: http://www.christeso.com/index.php/portfolio/snow-a-reactive-environment-inst…

Interactive Reactive Experiential Enviro

http://www.flickr.com/apps/video/stewart.swf?v=63881

A year or two ago when I started experimenting with creating applications that provide interactivity outside of a browser, in the environment, I thought it would take years before environmental experiences went to market. I thought there would be no demand by agencies for several years, no clients forward thinking enough to request interactive installations and certainly no companies focusing in on delivering these experiences. I was mistaken.

I’ve been surprised by the amount of buzz generated around interactive installations in the advertising industry. I’ve had thousands of visits to my blog from agencies, developers and the like with keywords such as Flash and Installations, Flash and Motion Detection and Interactive Installation. I guess I shouldn’t be shocked that an industry that is always hot for the latest ‘thing’ would push the medium forward. I’ve been pleasantly surprised to see several companies honing in on the niche that has presented itself in Interactive Installation. The fact these companies are specializing in it is a testament to the rising demand. There have also been several agencies that are developing their own internal lab to function as R&D into these areas. I commend these agencies for their forward thinking. Unfortunately, most of these agencies still haven’t figured out how to do traditional interactive profitably and or properly. That’s right, I said it. “Traditional Interactive”. Perhaps in these agencies this new medium will be able to skip over the old agency model of traditional “creatives” holding on to the last bastion of control over an interactive project, but I doubt it. Just as in traditional interactive I see Barbarianesque shops excelling in the Installation arena. We all see clients sidestepping traditional agencies in favor of new media agencies in both project work and AOR. I see no reason that trend would not continue in Reactive Media. After all the best interactive work results when the people designing the piece are also building the piece, concepting the piece, doing analytics on the piece and owning the piece.

All that said, I’ve just finished and launched the Interactive Installation located at 6th and Alder in Portland, Or. This is the second public installation I’ve done. I was shocked to see the amount of attention it has received, and is again a testament to how powerful this medium can be. Yes it helped that the client was/is downtown Portland. It got me on the news several times. But still… the excitement is there over the technology and the potential uses of moving experiences into the environment we all live in. I look forward to doing more.

If you’ll notice I’ve called this ‘thing’ several ‘things’ already. I’ve heard many terms bandied about. Some of these terms include Interactive Installation, Environmental Interactive, Reactive Installation, Interactive Projection, Enviro Interactive and Experiential Installation. To me none of these fully encompass what the medium and industry will be creating in the coming years. While most of my experiments have involved motion detection, there are many other avenues in this ‘thing’ to pursue. Auditory data aggregation, touch screen, sensors, robotics, industrial design melding with technology and interactive design just to name a few. I like the term Enviro Interactive. I think it gets close to encompassing the vast array of potential applications without confusing people with the word spelled out in full, ‘environmental’. On more than one occasion I’ve explained what I’m doing as Environmental Interactive only to get some vague response how nice it is that I’m being green.

So, what would you call it? Are you currently working in the medium? If so, in what capacity?

ps. In the news clip above notice that they captioned me as the ‘cyber snow artist’. From this point forward please address me as such. Anything less would be an insult of epic proportions.