On Github jonathanolson / slides-scenery
Jonathan OlsonPhET Interactive Simulations | University of Colorado Boulder
Most libraries focus on either Canvas, SVG or WebGL
Most libraries only support one renderer at a time
Most libraries have few of these
Higher performance by splitting content into layers
greenContainer.layerSplit = true; // will be isolated in a layer
// Create a scene graph over a positioned block-level element
var scene = new scenery.Scene( $( '#hello-world-scene' ) );
// Add our text
scene.addChild( new scenery.Text( 'Hello World', {
  centerX: 200, // the center of our text's bounds is at x = 200
  centerY: 50, // the center of our text's bounds is at y = 50
  font: '40px sans-serif', fill: '#eee'
} ) );
// Paint any changes (in this case, our text).
scene.updateScene();
        // simple shapes can be accelerated
scene.addChild( new scenery.Rectangle( 10, 10, 100, 80, {
  fill: '#f00', stroke: '#fff', lineWidth: 2
} ) );
scene.addChild( new scenery.Path( {
  shape: kite.Shape.regularPolygon( 8, 30 ),
  fill: '#0f0', x: 150, y: 50
} ) );
scene.addChild( new scenery.Path( {
  // Canvas-like Path API. Supports SVG Shape( 'M0 90Q155 50 0 10Z' )
  shape: new kite.Shape().lineTo( 0, 90 )
                         .quadraticCurveTo( 155, 50, 0, 10 )
                         .close(),
  fill: '#00f', x: 190
} ) );
        var imageUrl = 'http://phet.colorado.edu/sims/energy-skate-park/' +
               'energy-skate-park-basics-thumbnail.png';
// direct URL reference, but cannot position based on bounds
scene.addChild( new scenery.Image( imageUrl, {
  x: 100, y: -30, rotation: Math.PI / 6,
} ) );
// can also pass in HTMLImageElement or HTMLCanvasElement references
var img = document.createElement( 'img' );
img.src = imageUrl;
scene.addChild( new scenery.Image( img, { opacity: 0.25, scale: 2 } ) );
        var element = document.createElement( 'span' );
element.innerHTML =
  '<label style="display: inline;">Type in me:</label>' +
  '<input type="text">';
scene.addChild( new scenery.DOM( element, {
  x: 120, rotation: Math.PI / 6
} ) );
// HTML, with the same styling and positioning as Text
scene.addChild( new scenery.HTMLText( '<em>Italic</em> and <b>Bold</b> ', {
  fontSize: 30, bottom: 230, centerX: 200, fill: '#9aa'
} ) );
        first.fill = 'rgba(255,127,0,0.8)'; // full support for CSS colors
// linear gradients
secondBottom.fill = new scenery.LinearGradient( 0, 0, 100, 0 )
                               .addColorStop( 0, '#000' )
                               .addColorStop( 1, '#666' );
// radial gradients
secondTop.fill = new scenery.RadialGradient( 32, 32, 5, 64, 64, 60 )
                            .addColorStop( 0, '#0ff' )
                            .addColorStop( 1, 'rgba(0,127,255,0)' );
// patterns
var transform = dot.Matrix3.rotation2( Math.PI / 6 )
                           .timesMatrix( dot.Matrix3.scale( 0.3 ) );
third.fill = new scenery.Pattern( img ).setTransformMatrix( transform );
        first.stroke = 'rgba(255,127,0,0.8)'; // full support for CSS colors
// linear gradients
secondBottom.stroke = new scenery.LinearGradient( 0, 0, 100, 0 )
                                 .addColorStop( 0, '#000' )
                                 .addColorStop( 1, '#666' );
// radial gradients
secondTop.stroke = new scenery.RadialGradient( 32, 32, 5, 64, 64, 60 )
                              .addColorStop( 0, '#0ff' )
                              .addColorStop( 1, 'rgba(0,127,255,0)' );
// patterns
var transform = dot.Matrix3.rotation2( Math.PI / 6 )
                           .timesMatrix( dot.Matrix3.scale( 0.3 ) );
third.stroke = new scenery.Pattern( img ).setTransformMatrix( transform );
        Supports all Canvas line styles
// vertical layout path.top = 20; fastText.top = path.bottom + 20; accurateText.top = fastText.bottom + 20; // horizontal layout fastText.left = 20; // offset from the left path.centerX = fastText.centerX; // center the path above accurateText.left = path.left; // align the lower text with the pathPossible to implement higher-level layout on top
Multi-touch abstraction over DOM3/Touch/Pointer/MSPointer
section.cursor = 'pointer'; // change the cursor when the mouse is over a section
_.each( scene.children, function( section ) {
  // move each section individually
  section.addInputListener( new scenery.SimpleDragHandler() );
} );
        Under development:
And 2 more: Build an Atom and Balloons and Static Electricity
Require.js for modularization
Mostly feature-complete, working on performance
2D Shape Handling | phetsims.github.io/kite
Math, with a focus on linear algebra | phetsims.github.io/dot
var v = dot( 10, -5 ) // shorthand for Vector2, used for points and vectors
                      // v.x and v.y are the components
v.normalized().times( 5 ).plus( dot( 1, 2 ) ).x  // immutable, matches formulas
v.normalize().multiply( 5 ).add( dot( 1, 2 ) ).x // mutable, minimizes GCs
dot.Matrix3.rotation2( Math.PI / 6 ).timesVector2( v )    // immutable
dot.Matrix3.rotation2( Math.PI / 6 ).multiplyVector2( v ) // mutable
        If opacity is applied to a node whose children are across different layers, they will need to be handled differently:
<!-- layers before --> <div style="opacity: 0.6;"> <canvas><!-- red circle layer --></canvas> <svg><!-- blue circle layer --></svg> </div> <!-- layers after -->
Mixed Canvas/SVG/DOM not accessible by default
Soon: Creating DOM peers for each interactive node, with subtree control over the tab order
(or catch me after)
Jonathan Olson
github.com/jonathanolson | jonathan.olson@colorado.edu
Thanks to the PhET team (phet.colorado.edu), especially Sam Reid, Chris Malley, John Blanco and director Kathy Perkins