Make Art Not Money

Creative Code with JavaScript

Brad Bouse | @bradbouse

CascadiaJS, November 2013

Hi.

I'm @bradbouse.

Film School → Ad Agencies → Startups → Here

Quit your job.

Make art instead.

Forget those recruiters!

Make something useless.

Don't really quit.

But give this a try. It has worked for me.

Between Page and Screen

Try it.

What I'd Learn?

  • New skills: 3D, augmented reality.
  • Obsession with frame rate.
  • Different perspective on interfaces.

Why creative code?

Most web dev is moving text around.

Try something new.

So, don't quit your job.

But take a day off.

Experiments

It won't work in IE

It might not work on Windows.

It might not work without developer flags.

It might need expensive hardware.

And that's ok.

Creative code is an experiment

with the goal of

surprising and delighting.

  1. JS is a great platform for creative code.
  2. Basics for creating graphics.
  3. Demo a Leap app.
  4. Give you something to try at home.

JavaScript is great for Creative Code

Coming from a recovering ActionScripter.

JS Engines are fast (thanks v8!)

Modern browsers: Canvas, SVG, CSS3

Moderner browsers: webGL and webRTC

Libraries: graphics/physics/3D/particles

Input devices: Kinect, Leap, Oculus Rift, Arduino

JS Platform

Ubiquitous, fast, and powerful.

Other platforms

Flash (ActionScript)

Processing (Java-ish)

OpenFrameworks (C++)

Cinder (C++)

  1. JS is a great platform for creative code.
  2. Basics for creating graphics.
  3. Demo a Leap app.
  4. Give you something to try at home.

Making pretty pictures.

Canvas vs. SVG

Canvas writes pixels.

  • Advantage: extremely fast.
  • Disadvantage: DOM has no idea what's going on.

Canvas: Browser sees one big square.

Square

SVG writes vectors.

  • Advantage: DOM-friendly.
  • Disadvantage: constrained by number of elements.
  • D3.js

SVG: Browser sees a square inside a square.

Square

Canvas Libraries

  • Hybrid approach
  • SVG-ish abstraction on top of canvas
  • JavaScript knows about the objects, but not the DOM.
  • paper.js, easel.js, and many others

Canvas Libraries: JS sees two squares, browser sees one.

Square

Why does it matter?

Speed matters.

Demo

And then there's webGL.

GPUs aren't just for mining BitCoin.

Demo

Canvas vs. SVG vs. webGL

  • webGL is not broadly supported (yet).
  • Radically different way of drawing objects.
  • Magnitudes faster for the right application.

Libraries

http://wholepixel.com/libs

Inspiration

http://wholepixel.com/inspiration

  1. JS is a great platform for creative code.
  2. Basics for creating graphics
  3. Demo a Leap app
  4. Give you something to try at home.

Get the user involved.

We're looking for surprise and delight.

There's always the mouse...

But what haven't you clicked?

Surprise and delight

Touch

Webcam! (Demo)

External hardware (Arduino, Kinect, Oculus, and Leap)

The Leap Motion

Leap Controller
  • Detects hand and finger position
  • Two cameras and three IR LEDs detect reflection
  • Does fancy math
  • Started shipping July, 2013
  • $80

Connecting to JS

  • Tray application
  • JavaScript SDK

Wiring it up.

            

...
@controller = new Leap.Controller({enableGestures: true})

//Set up a method to listen for frames...
@controller.loop(
  (frame)->
    //Do something awesome here.
)

//Listen to events from Leap
@controller.on('ready', ()->console.log("LEAP: ready"))
@controller.on('connect', ()->console.log("LEAP: connect"))
@controller.on('disconnect', ()->console.log("LEAP: disconnect"))
            
          

The frame

~20-90fps

            
{
  "currentFrameRate":41.8666,
  "gestures":[

  ],
  "hands":[
    {
      "direction":[
        -0.0266162,
        0.146813,
        -0.988806
      ],
      "id":77,
      "palmNormal":[
        -0.389214,
        -0.912623,
        -0.125025
      ],
      "palmPosition":[
        115.035,
        171.469,
        -41.5293
      ],
      "palmVelocity":[
        5.43727,
        -1.82765,
        15.3623
      ],
      "r":[
        [
          0.981607,
          0.108195,
          -0.157292
        ],
        [
          -0.0838155,
          0.984489,
          0.154128
        ],
        [
          0.171529,
          -0.13811,
          0.97545
        ]
      ],
      "s":1.20843,
      "sphereCenter":[
        137.828,
        163.689,
        -96.022
      ],
      "sphereRadius":53.52,
      "stabilizedPalmPosition":[
        115.845,
        169.405,
        -42.1059
      ],
      "t":[
        66.3909,
        -5.94365,
        -29.0868
      ],
      "timeVisible":7.79126
    }
  ],
  "id":576683,
  "interactionBox":{
    "center":[
      0,
      200,
      0
    ],
    "size":[
      221.418,
      221.418,
      154.742
    ]
  },
  "pointables":[
    {
      "direction":[
        0.0311235,
        -0.0974021,
        -0.994758
      ],
      "handId":77,
      "id":95,
      "length":87.6252,
      "stabilizedTipPosition":[
        126.97,
        159.292,
        -155.551
      ],
      "timeVisible":2.66912,
      "tipPosition":[
        126.888,
        162.142,
        -155.141
      ],
      "tipVelocity":[
        5.98264,
        -0.22555,
        8.8473
      ],
      "tool":false,
      "touchDistance":0.139815,
      "touchZone":"hovering"
    },
    {
      "direction":[
        -0.0886096,
        -0.231428,
        -0.968808
      ],
      "handId":77,
      "id":65,
      "length":77.2424,
      "stabilizedTipPosition":[
        85.1323,
        160.774,
        -143.87
      ],
      "timeVisible":3.17219,
      "tipPosition":[
        85.3095,
        163.473,
        -144.145
      ],
      "tipVelocity":[
        7.06236,
        -1.15117,
        -1.18688
      ],
      "tool":false,
      "touchDistance":-0.231083,
      "touchZone":"touching"
    },
    {
      "direction":[
        0.265041,
        0.116697,
        -0.95715
      ],
      "handId":77,
      "id":32,
      "length":72.2835,
      "stabilizedTipPosition":[
        172.964,
        173.215,
        -144.496
      ],
      "timeVisible":0.433577,
      "tipPosition":[
        172.193,
        173.445,
        -144.096
      ],
      "tipVelocity":[
        9.59312,
        4.66446,
        -2.93894
      ],
      "tool":false,
      "touchDistance":0.333278,
      "touchZone":"hovering"
    },
    {
      "direction":[
        0.605547,
        0.0398785,
        -0.794809
      ],
      "handId":77,
      "id":74,
      "length":52.6733,
      "stabilizedTipPosition":[
        206.995,
        152.038,
        -88.7095
      ],
      "timeVisible":0.047254,
      "tipPosition":[
        207.907,
        152.12,
        -89.3827
      ],
      "tipVelocity":[
        59.7907,
        1.5625,
        -30.8251
      ],
      "tool":false,
      "touchDistance":0.333333,
      "touchZone":"hovering"
    },
    {
      "direction":[
        -0.388312,
        0.617854,
        -0.683718
      ],
      "handId":77,
      "id":45,
      "length":44.7898,
      "stabilizedTipPosition":[
        29.7561,
        219.239,
        -52.1798
      ],
      "timeVisible":3.17219,
      "tipPosition":[
        28.3511,
        219.518,
        -51.9544
      ],
      "tipVelocity":[
        9.13187,
        -17.3379,
        6.18593
      ],
      "tool":false,
      "touchDistance":-0.150288,
      "touchZone":"touching"
    }
  ],
  "r":[
    [
      0.690598,
      -0.710438,
      -0.135473
    ],
    [
      0.645118,
      0.689778,
      -0.328677
    ],
    [
      0.32695,
      0.139587,
      0.934676
    ]
  ],
  "s":-112.951,
  "t":[
    -21556.7,
    -18003.8,
    4323.1
  ],
  "timestamp":334232761045
}
            
          

Enough already, let's see it...

Demo

Interaction

Motion over time.

            
//Motion scale
frame.scaleFactor(sinceFrame)

//Linear action
frame.translation(sinceFrame)

//Rotation
frame.rotationAngle(sinceFrame, axis)
            
          

Let's see that...

Demo

Gestures

  • No mouse! Eek!
  • Kinect - poses
  • Google Glass - "OK Glass"
  • Design around your limitations.

Built-in Leap Gestures

  • CircleGesture - circular movement by finger.
  • SwipeGesture - straight line by hand with fingers extended.
  • ScreenTapGesture - forward tapping movement by finger.
  • KeyTapGesture - downward tapping movement by finger.

Catching a swipe

            
catchGesture:(gesture)->
  # Fired continuously *during* every gesture
  # We only want swipes that look intentional
  if gesture.type=="swipe" && gesture.state !="start"
    if gesture.duration > 500  && !@gesturesMap[gesture.id]
      #how far did the user travel in one direction?
      distance = Math.abs(gesture.startPosition[0] - gesture.position[0])
      if distance > 100
        console.log("SWIPE:", gesture)
        // Do something with the gesture.
            
          

And with gestures...

Demo

Try it out

http://github.com/doolittle/magicfingers

Takeaways

  • Performance is really important.
  • Many atomic actions.
  • Control event flow.
  • Interface problem solving.
  • Abstraction.
  1. JS is a great platform for creative code.
  2. Basics for creating graphics
  3. Demo a Leap app
  4. Give you something to try at home.

How to get started?

Conceptual Art

"In conceptual art the idea or concept is the most important aspect of the work. When an artist uses a conceptual form of art, it means that all of the planning and decisions are made beforehand and the execution is a perfunctory affair. The idea becomes a machine that makes the art." -- Sol LeWitt
Lewitt Instructions
Lewitt Installation
Lewitt Complete
Lewitt Certificate
Lewitt Instructions
Lewitt Ticket

Better solve Sol...

http://github.com/wholepixel/solving-sol

Try it with paper.js, d3.js, processing.js or anything else.

Take a day off.

Try something new.

Thanks!

Let me know if you make anything!

@bradbouse

bradbouse / gmail

Slides at wholepixel.com/cascadia