SlideShare a Scribd company logo
WebGL para JavaScripters



                  Luz Caballero
Luz Caballero - @gerbille

        Web Opener
Agenda
• Que es WebGL?
• Para qué se puede usar?
• Cómo funciona?
• Lo que hay que saber para empezar
• Un poco de código
Qué es WebGL ?
OpenGL   OpenGL ES   WebGL
desktop   mobile
<canvas id=‘c’ width=‘100’ height=‘100’></canvas>


document.getElementById(‘c’).getContext(‘webgl’)
Para qué se puede usar?
•   Visualización de datos

•   Creative coding

•   Arte

•   Environments de diseño 3D

•   Videos de música

•   Graficación de funciones matemáticas

•   Modelado de objectos y espacios 3D

•   Creación de texturas

•   Simulaciones físicas

•   ...procesamiento rápido de cualquier tipo de
    datos
visualización de datos
creative coding
arte
environments de diseño 3D
videos de música
graficación de funciones matemáticas
modelado de objetos y espacios 3D
juegos
creación de texturas
simulaciones físicas
Cómo funciona?
Webgl para JavaScripters
JavaScript

WebGL JS API



               GPU (Compiled Program)
JavaScript


WebGL JS API


GLSL API        Vertex Shader




GLSL API       Fragment Shader
Lo que hay que saber
   para empezar
The 3D scene




          image source: http://computer.yourdictionary.com/graphics
Choosing a library
• Three.js
• PhiloGL
• GLGE
• J3D
• TDL
• ...
desktop   mobile
WebGL inspector
Un poco de código
Webgl para JavaScripters
<!DOCTYPE html>
<html>
  <head>
    <title>Learning WebGL lesson 11 in PhiloGL</title>
    <link href="path/to/file.css" type="text/css" rel="stylesheet"
media="screen" />
    <script src="path/to/PhiloGL.js"></script>
    <script src="path/to/index.js"></script>
  </head>
        
  <body onload="webGLStart();">
    <canvas id="lesson11-canvas" width="500" height="500"></canvas>
    <!-- more html elements here... -->
  </body>
</html>
function webGLStart() {
  var pos, $ = function(d) { return document.getElementById(d); };
    
  //Create moon
  var moon = new PhiloGL.O3D.Sphere({
    nlat: 30,
    nlong: 30,
    radius: 2,
    textures: 'moon.gif'
  });
  //Create application
  PhiloGL('lesson11-canvas', {
    camera: {
      position: {
        x: 0, y: 0, z: -7
      }
    },
    textures: {
      src: ['moon.gif'],
      parameters: [{
        name: 'TEXTURE_MAG_FILTER',
        value: 'LINEAR'
      }, {
        name: 'TEXTURE_MIN_FILTER',
        value: 'LINEAR_MIPMAP_NEAREST',
        generateMipmap: true
      }]
    },
    events: {
      onDragStart: function(e) {
        pos = {
          x: e.x,
          y: e.y
        };
      },
      onDragMove: function(e) {
        var z = this.camera.position.z,
        sign = Math.abs(z) / z;

          moon.rotation.y += -(pos.x - e.x) / 100;
          moon.rotation.x += sign * (pos.y - e.y) / 100;
          moon.update();
          pos.x = e.x;
          pos.y = e.y;
        },
        onMouseWheel: function(e) {
          e.stop();
          var camera = this.camera;
          camera.position.z += e.wheel;
          camera.update();
        }
      },
      onError: function() {
        alert("There was an error creating the app.");
      },
      onLoad: function(app) {
        //Unpack app properties
        var gl = app.gl,
        program = app.program,
        scene = app.scene,
        canvas = app.canvas,
        camera = app.camera;

        //get light config from forms
      lighting = $('lighting'),
      ambient = {
        r: $('ambientR'),
        g: $('ambientG'),
        b: $('ambientB')
      },
      direction = {
        x: $('lightDirectionX'),
        y: $('lightDirectionY'),
        z: $('lightDirectionZ'),

        r: $('directionalR'),
        g: $('directionalG'),
        b: $('directionalB')
      };
      //Basic gl setup
      gl.clearColor(0.0, 0.0, 0.0, 1.0);
      gl.clearDepth(1.0);
      gl.enable(gl.DEPTH_TEST);
      gl.depthFunc(gl.LEQUAL);
      gl.viewport(0, 0, canvas.width, canvas.height);
//Add object to the scene
      scene.add(moon);
      
      //Draw the scene
      draw();        

    function draw() {
      //clear the screen
      gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
      //Setup lighting
      var lights = scene.config.lights;
      lights.enable = lighting.checked;
      lights.ambient = {
        r: +ambient.r.value,
        g: +ambient.g.value,
        b: +ambient.b.value
      };
      lights.directional = {
        color: {
          r: +direction.r.value,
          g: +direction.g.value,
          b: +direction.b.value
        },
        direction: {
          x: +direction.x.value,
          y: +direction.y.value,
          z: +direction.z.value
        }
      };
  
      //render moon
      scene.render();
      //Animate
      Fx.requestAnimationFrame(draw);
      }
    }
  });
}
Webgl para JavaScripters
<script>
    
if ( ! Detector.webgl ) Detector.addGetWebGLMessage();

var SCREEN_WIDTH = window.innerWidth;
var SCREEN_HEIGHT = window.innerHeight;
var FLOOR = 0;

var container;

var camera, scene;
var webglRenderer;

var zmesh, geometry;

var mouseX = 0, mouseY = 0;

var windowHalfX = window.innerWidth / 2;
var windowHalfY = window.innerHeight / 2;

document.addEventListener( 'mousemove', onDocumentMouseMove, false );
init();
animate();
function init() {
  container = document.createElement( 'div' );
  document.body.appendChild( container );
            
  // camera
  camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 );
  camera.position.z = 75;
            
  // scene
  scene = new THREE.Scene();

  // lights
  var ambient = new THREE.AmbientLight( 0xffffff );
  scene.add( ambient );
            
  // more lights
  var directionalLight = new THREE.DirectionalLight( 0xffeedd );
  directionalLight.position.set( 0, -70, 100 ).normalize();
  scene.add( directionalLight );
}
// renderer
webglRenderer = new THREE.WebGLRenderer();
webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT );
webglRenderer.domElement.style.position = "relative";
container.appendChild( webglRenderer.domElement );

// loader
var loader = new THREE.JSONLoader(),
loader.load( { model: "obj/church/church.js", callback: createScene } );
                                         
function createScene( geometry ) {
  zmesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );
  zmesh.position.set( 0, 16, 0 );
  zmesh.scale.set( 1, 1, 1 );
  scene.add( zmesh );
}

function onDocumentMouseMove(event) {
  mouseX = ( event.clientX - windowHalfX );
  mouseY = ( event.clientY - windowHalfY );
}
function animate() {
  requestAnimationFrame( animate );
  render();
}

function render() {
  zmesh.rotation.set(-mouseY/500 + 1, -mouseX/200, 0);
  webglRenderer.render( scene, camera );
}
</script>                                         
Resources
•   An Introduction to WebGL @ dev.Opera
•   PhiloGL
•   PhiloGL tutorial
•   WebGL w/o a library @ dev.Opera
•   Porting 3D models to WebGL @ dev.Opera
•   News and resources @ the Learning WebGL blog
•   WebGL w/o a library @ Learning WebGL
•   Three.js
•   Three.js tutorial
•   WebGL FAQ
•   The Khronos WebGL forum
•   WebGL-dev mailing list
Thanks!

@gerbille

More Related Content

What's hot (19)

PPTX
AngularJS Routing
Eyal Vardi
 
KEY
Object-Oriented Javascript
kvangork
 
PDF
Integrating Angular js & three.js
Josh Staples
 
PDF
Javascript is your (Auto)mate
Codemotion
 
PPTX
The next step, part 2
Pat Cavit
 
PPTX
Developing Web Graphics with WebGL
Tony Parisi
 
PDF
Shibuya.js Lightning Talks
jeresig
 
PPTX
AngularJS Compile Process
Eyal Vardi
 
PPTX
SenchaCon 2016: Improve Workflow Driven Applications with Ext JS Draw Package...
Sencha
 
PDF
Dion Almaer & Ben Galbraith - Build Once, Deploy Everywhere
Carsonified Team
 
PDF
Cyclejs introduction
Arye Lukashevski
 
PPTX
AngularJS Animations
Eyal Vardi
 
PDF
Browsers with Wings
Remy Sharp
 
PDF
jQuery: Events, Animation, Ajax
Constantin Titarenko
 
PDF
What's new in iOS9
CocoaHeads France
 
PPTX
Taming that client side mess with Backbone.js
Jarod Ferguson
 
PDF
How Kris Writes Symfony Apps
Kris Wallsmith
 
PDF
Processing and Processing.js
jeresig
 
PDF
CQRS and Event Sourcing in a Symfony application
Samuel ROZE
 
AngularJS Routing
Eyal Vardi
 
Object-Oriented Javascript
kvangork
 
Integrating Angular js & three.js
Josh Staples
 
Javascript is your (Auto)mate
Codemotion
 
The next step, part 2
Pat Cavit
 
Developing Web Graphics with WebGL
Tony Parisi
 
Shibuya.js Lightning Talks
jeresig
 
AngularJS Compile Process
Eyal Vardi
 
SenchaCon 2016: Improve Workflow Driven Applications with Ext JS Draw Package...
Sencha
 
Dion Almaer & Ben Galbraith - Build Once, Deploy Everywhere
Carsonified Team
 
Cyclejs introduction
Arye Lukashevski
 
AngularJS Animations
Eyal Vardi
 
Browsers with Wings
Remy Sharp
 
jQuery: Events, Animation, Ajax
Constantin Titarenko
 
What's new in iOS9
CocoaHeads France
 
Taming that client side mess with Backbone.js
Jarod Ferguson
 
How Kris Writes Symfony Apps
Kris Wallsmith
 
Processing and Processing.js
jeresig
 
CQRS and Event Sourcing in a Symfony application
Samuel ROZE
 

Viewers also liked (8)

PPT
творчество братьев леннен
andry2517
 
KEY
Des interfaces futuristes utilisant des APIs web
gerbille
 
PDF
Speed in the Opera mobile browsers
gerbille
 
PDF
Speed in the Opera mobile browsers
gerbille
 
DOCX
Growth model 2,5% de sodio
Diana Raimondo
 
DOCX
Growth model con 0,5% de sodio
Diana Raimondo
 
KEY
What's new in the Opera mobile browsers
gerbille
 
PPT
Device dis(orientation)?
gerbille
 
творчество братьев леннен
andry2517
 
Des interfaces futuristes utilisant des APIs web
gerbille
 
Speed in the Opera mobile browsers
gerbille
 
Speed in the Opera mobile browsers
gerbille
 
Growth model 2,5% de sodio
Diana Raimondo
 
Growth model con 0,5% de sodio
Diana Raimondo
 
What's new in the Opera mobile browsers
gerbille
 
Device dis(orientation)?
gerbille
 
Ad

Similar to Webgl para JavaScripters (20)

PDF
Leaving Flatland: Getting Started with WebGL- SXSW 2012
philogb
 
KEY
Getting Started with WebGL
Chihoon Byun
 
PDF
WebGL and three.js
Anton Narusberg
 
KEY
WebGL Awesomeness
Stephan Seidt
 
ODP
Introduction to threejs
Gareth Marland
 
PPTX
HTML5DevConf 2013 (October): WebGL is a game changer!
Iker Jamardo
 
PDF
"Graphical fun With WebGL shaders", Martin Splitt
Fwdays
 
PDF
Augmented reality in web rtc browser
ALTANAI BISHT
 
PDF
Creating Applications with WebGL and Three.js
Future Insights
 
PDF
WebGL
EU Edge
 
PDF
Learning WebGLで学ぶWebGL入門
nakamura001
 
PDF
Introduction to Webgl by Rachel Prudden
TechExeter
 
PDF
ENEI16 - WebGL with Three.js
José Ferrão
 
PDF
140716 : 同業前端聚會分享 - webgl 與 three.js
angelliya00
 
PDF
Installing Games Sucks, Learn WebGL
Corey Clark, Ph.D.
 
PDF
OpenGL Starter L02
Mohammad Shaker
 
PPTX
[JS EXPERIENCE 2018] Jogos em JavaScript com WebGL - Juliana Negreiros, Codem...
iMasters
 
PDF
Getting Started with OpenGL ES
John Wilker
 
PDF
A Novice's Guide to WebGL
Krzysztof Kula
 
PDF
WebGL demos showcase
Yukio Andoh
 
Leaving Flatland: Getting Started with WebGL- SXSW 2012
philogb
 
Getting Started with WebGL
Chihoon Byun
 
WebGL and three.js
Anton Narusberg
 
WebGL Awesomeness
Stephan Seidt
 
Introduction to threejs
Gareth Marland
 
HTML5DevConf 2013 (October): WebGL is a game changer!
Iker Jamardo
 
"Graphical fun With WebGL shaders", Martin Splitt
Fwdays
 
Augmented reality in web rtc browser
ALTANAI BISHT
 
Creating Applications with WebGL and Three.js
Future Insights
 
WebGL
EU Edge
 
Learning WebGLで学ぶWebGL入門
nakamura001
 
Introduction to Webgl by Rachel Prudden
TechExeter
 
ENEI16 - WebGL with Three.js
José Ferrão
 
140716 : 同業前端聚會分享 - webgl 與 three.js
angelliya00
 
Installing Games Sucks, Learn WebGL
Corey Clark, Ph.D.
 
OpenGL Starter L02
Mohammad Shaker
 
[JS EXPERIENCE 2018] Jogos em JavaScript com WebGL - Juliana Negreiros, Codem...
iMasters
 
Getting Started with OpenGL ES
John Wilker
 
A Novice's Guide to WebGL
Krzysztof Kula
 
WebGL demos showcase
Yukio Andoh
 
Ad

Recently uploaded (20)

PDF
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
PDF
Python basic programing language for automation
DanialHabibi2
 
PDF
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
PDF
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
PPTX
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
PDF
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
PDF
Timothy Rottach - Ramp up on AI Use Cases, from Vector Search to AI Agents wi...
AWS Chicago
 
PPTX
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
PDF
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
PDF
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
PDF
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
PDF
The Builder’s Playbook - 2025 State of AI Report.pdf
jeroen339954
 
PDF
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
PPTX
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
PPTX
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
PDF
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
PPTX
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
PDF
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
PDF
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
PDF
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 
Log-Based Anomaly Detection: Enhancing System Reliability with Machine Learning
Mohammed BEKKOUCHE
 
Python basic programing language for automation
DanialHabibi2
 
DevBcn - Building 10x Organizations Using Modern Productivity Metrics
Justin Reock
 
SWEBOK Guide and Software Services Engineering Education
Hironori Washizaki
 
"Autonomy of LLM Agents: Current State and Future Prospects", Oles` Petriv
Fwdays
 
New from BookNet Canada for 2025: BNC BiblioShare - Tech Forum 2025
BookNet Canada
 
Timothy Rottach - Ramp up on AI Use Cases, from Vector Search to AI Agents wi...
AWS Chicago
 
AUTOMATION AND ROBOTICS IN PHARMA INDUSTRY.pptx
sameeraaabegumm
 
CIFDAQ Weekly Market Wrap for 11th July 2025
CIFDAQ
 
[Newgen] NewgenONE Marvin Brochure 1.pdf
darshakparmar
 
NewMind AI - Journal 100 Insights After The 100th Issue
NewMind AI
 
The Builder’s Playbook - 2025 State of AI Report.pdf
jeroen339954
 
Newgen Beyond Frankenstein_Build vs Buy_Digital_version.pdf
darshakparmar
 
Building Search Using OpenSearch: Limitations and Workarounds
Sease
 
Q2 FY26 Tableau User Group Leader Quarterly Call
lward7
 
Jak MŚP w Europie Środkowo-Wschodniej odnajdują się w świecie AI
dominikamizerska1
 
MSP360 Backup Scheduling and Retention Best Practices.pptx
MSP360
 
Bitcoin for Millennials podcast with Bram, Power Laws of Bitcoin
Stephen Perrenod
 
How Startups Are Growing Faster with App Developers in Australia.pdf
India App Developer
 
Presentation - Vibe Coding The Future of Tech
yanuarsinggih1
 

Webgl para JavaScripters

  • 1. WebGL para JavaScripters Luz Caballero
  • 2. Luz Caballero - @gerbille Web Opener
  • 3. Agenda • Que es WebGL? • Para qué se puede usar? • Cómo funciona? • Lo que hay que saber para empezar • Un poco de código
  • 5. OpenGL OpenGL ES WebGL
  • 6. desktop mobile
  • 7. <canvas id=‘c’ width=‘100’ height=‘100’></canvas> document.getElementById(‘c’).getContext(‘webgl’)
  • 8. Para qué se puede usar?
  • 9. Visualización de datos • Creative coding • Arte • Environments de diseño 3D • Videos de música • Graficación de funciones matemáticas • Modelado de objectos y espacios 3D • Creación de texturas • Simulaciones físicas • ...procesamiento rápido de cualquier tipo de datos
  • 12. arte
  • 16. modelado de objetos y espacios 3D
  • 22. JavaScript WebGL JS API GPU (Compiled Program)
  • 23. JavaScript WebGL JS API GLSL API Vertex Shader GLSL API Fragment Shader
  • 24. Lo que hay que saber para empezar
  • 25. The 3D scene image source: http://computer.yourdictionary.com/graphics
  • 26. Choosing a library • Three.js • PhiloGL • GLGE • J3D • TDL • ...
  • 27. desktop mobile
  • 29. Un poco de código
  • 31. <!DOCTYPE html> <html>   <head>     <title>Learning WebGL lesson 11 in PhiloGL</title>     <link href="path/to/file.css" type="text/css" rel="stylesheet" media="screen" />     <script src="path/to/PhiloGL.js"></script>     <script src="path/to/index.js"></script>   </head>            <body onload="webGLStart();">     <canvas id="lesson11-canvas" width="500" height="500"></canvas>     <!-- more html elements here... -->   </body> </html>
  • 32. function webGLStart() {   var pos, $ = function(d) { return document.getElementById(d); };        //Create moon   var moon = new PhiloGL.O3D.Sphere({     nlat: 30,     nlong: 30,     radius: 2,     textures: 'moon.gif'   });
  • 33.   //Create application   PhiloGL('lesson11-canvas', {     camera: {       position: {         x: 0, y: 0, z: -7       }     },     textures: {       src: ['moon.gif'],       parameters: [{         name: 'TEXTURE_MAG_FILTER',         value: 'LINEAR'       }, {         name: 'TEXTURE_MIN_FILTER',         value: 'LINEAR_MIPMAP_NEAREST',         generateMipmap: true       }]     },     events: {       onDragStart: function(e) {         pos = {           x: e.x,           y: e.y         };       },       onDragMove: function(e) {         var z = this.camera.position.z,         sign = Math.abs(z) / z;         moon.rotation.y += -(pos.x - e.x) / 100;         moon.rotation.x += sign * (pos.y - e.y) / 100;         moon.update();         pos.x = e.x;         pos.y = e.y;       },       onMouseWheel: function(e) {         e.stop();         var camera = this.camera;         camera.position.z += e.wheel;         camera.update();       }     },
  • 34.     onError: function() {       alert("There was an error creating the app.");     },     onLoad: function(app) {       //Unpack app properties       var gl = app.gl,       program = app.program,       scene = app.scene,       canvas = app.canvas,       camera = app.camera;       //get light config from forms     lighting = $('lighting'),     ambient = {       r: $('ambientR'),       g: $('ambientG'),       b: $('ambientB')     },     direction = {       x: $('lightDirectionX'),       y: $('lightDirectionY'),       z: $('lightDirectionZ'),       r: $('directionalR'),       g: $('directionalG'),       b: $('directionalB')     };     //Basic gl setup     gl.clearColor(0.0, 0.0, 0.0, 1.0);     gl.clearDepth(1.0);     gl.enable(gl.DEPTH_TEST);     gl.depthFunc(gl.LEQUAL);     gl.viewport(0, 0, canvas.width, canvas.height);
  • 35. //Add object to the scene     scene.add(moon);          //Draw the scene     draw();             function draw() {       //clear the screen       gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);       //Setup lighting       var lights = scene.config.lights;       lights.enable = lighting.checked;       lights.ambient = {         r: +ambient.r.value,         g: +ambient.g.value,         b: +ambient.b.value       };       lights.directional = {         color: {           r: +direction.r.value,           g: +direction.g.value,           b: +direction.b.value         },         direction: {           x: +direction.x.value,           y: +direction.y.value,           z: +direction.z.value         }       };          //render moon       scene.render();       //Animate       Fx.requestAnimationFrame(draw);       }     }   }); }
  • 37. <script>      if ( ! Detector.webgl ) Detector.addGetWebGLMessage(); var SCREEN_WIDTH = window.innerWidth; var SCREEN_HEIGHT = window.innerHeight; var FLOOR = 0; var container; var camera, scene; var webglRenderer; var zmesh, geometry; var mouseX = 0, mouseY = 0; var windowHalfX = window.innerWidth / 2; var windowHalfY = window.innerHeight / 2; document.addEventListener( 'mousemove', onDocumentMouseMove, false ); init(); animate();
  • 38. function init() {   container = document.createElement( 'div' );   document.body.appendChild( container );                // camera   camera = new THREE.PerspectiveCamera( 75, SCREEN_WIDTH / SCREEN_HEIGHT, 1, 100000 );   camera.position.z = 75;                // scene   scene = new THREE.Scene();   // lights   var ambient = new THREE.AmbientLight( 0xffffff );   scene.add( ambient );                // more lights   var directionalLight = new THREE.DirectionalLight( 0xffeedd );   directionalLight.position.set( 0, -70, 100 ).normalize();   scene.add( directionalLight ); }
  • 39. // renderer webglRenderer = new THREE.WebGLRenderer(); webglRenderer.setSize( SCREEN_WIDTH, SCREEN_HEIGHT ); webglRenderer.domElement.style.position = "relative"; container.appendChild( webglRenderer.domElement ); // loader var loader = new THREE.JSONLoader(), loader.load( { model: "obj/church/church.js", callback: createScene } );                                           function createScene( geometry ) {   zmesh = new THREE.Mesh( geometry, new THREE.MeshFaceMaterial() );   zmesh.position.set( 0, 16, 0 );   zmesh.scale.set( 1, 1, 1 );   scene.add( zmesh ); } function onDocumentMouseMove(event) {   mouseX = ( event.clientX - windowHalfX );   mouseY = ( event.clientY - windowHalfY ); }
  • 40. function animate() {   requestAnimationFrame( animate );   render(); } function render() {   zmesh.rotation.set(-mouseY/500 + 1, -mouseX/200, 0);   webglRenderer.render( scene, camera ); } </script>                                         
  • 41. Resources • An Introduction to WebGL @ dev.Opera • PhiloGL • PhiloGL tutorial • WebGL w/o a library @ dev.Opera • Porting 3D models to WebGL @ dev.Opera • News and resources @ the Learning WebGL blog • WebGL w/o a library @ Learning WebGL • Three.js • Three.js tutorial • WebGL FAQ • The Khronos WebGL forum • WebGL-dev mailing list