diff --git a/example/webgl/webgl-0001-basic.html b/example/webgl/webgl-0001-basic.html
new file mode 100644
index 0000000000000000000000000000000000000000..c7a099dd2368226ba9aad72f3c9e034effac8de3
--- /dev/null
+++ b/example/webgl/webgl-0001-basic.html
@@ -0,0 +1,91 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>WebGL</title>
+
+    <style type="text/css">
+      body { background-color: grey;}
+      canvas { background-color: white;}
+    </style>
+    <script src="../../dist/skulpt.js" type="text/javascript"></script>
+    <script src="../../dist/builtin.js" type="text/javascript"></script>
+  </head>
+  <body>
+    <h1>WebGL</h1>
+
+    <form>
+      <textarea id="code" name="code" rows="40" cols="120">
+import webgl
+
+gl = webgl.Context("my-canvas")
+
+vs = gl.createShader(gl.VERTEX_SHADER) 
+gl.shaderSource(vs, "attribute vec3 aVertexPosition; void main(void) { gl_Position = vec4(aVertexPosition, 1.0); }")
+gl.compileShader(vs)
+print "Vertex shader COMPILE_STATUS: " + str(gl.getShaderParameter(vs, gl.COMPILE_STATUS))
+fs = gl.createShader(gl.FRAGMENT_SHADER) 
+gl.shaderSource(fs, "void main(void) { gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); }")
+gl.compileShader(fs)
+print "Fragment shader COMPILE_STATUS: " + str(gl.getShaderParameter(fs, gl.COMPILE_STATUS))
+
+program = gl.createProgram()
+gl.attachShader(program, vs)
+gl.attachShader(program, fs)
+gl.linkProgram(program)
+print "Program LINK_STATUS: " + str(gl.getProgramParameter(program, gl.LINK_STATUS))
+gl.useProgram(program)
+
+triangleVertices = [-0.5,  0.5, 0.0,
+                     0.0,  0.0, 0.0,
+                    -0.5, -0.5, 0.0,
+                     0.5,  0.5, 0.0,
+                     0.0,  0.0, 0.0,
+                     0.5, -0.5, 0.0]
+
+trianglesVerticeBuffer = gl.createBuffer()
+gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer)
+gl.bufferData(gl.ARRAY_BUFFER, webgl.Float32Array(triangleVertices), gl.STATIC_DRAW)
+
+vertexPositionAttribute = gl.getAttribLocation(program, "aVertexPosition")
+gl.enableVertexAttribArray(vertexPositionAttribute)
+gl.bindBuffer(gl.ARRAY_BUFFER, trianglesVerticeBuffer)
+gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, False, 0, 0)
+gl.drawArrays(gl.TRIANGLES, 0, 6)
+      </textarea>
+      <button type="button" onclick="runit()">Run</button>
+    </form>
+    <canvas id="my-canvas" height="248" width="400">
+      Your browser does not support the HTML5 canvas element.
+    </canvas>
+    <pre id="my-output" ></pre>
+    <script>
+      function outputHandler(text) {
+        var output = document.getElementById("my-output");
+        output.innerHTML = output.innerHTML + text.replace(/</g, '&lt;');
+      }
+
+      function builtinRead(x) {
+        if (Sk.builtinFiles === undefined || Sk.builtinFiles["files"][x] === undefined) {
+          throw "File not found: '" + x + "'";
+        }
+        return Sk.builtinFiles["files"][x];
+      }
+
+      function runit() {
+        var prog = document.getElementById("code").value;
+        // Clear the output
+        document.getElementById("my-output").innerHTML = '';
+        Sk.canvas = "my-canvas";
+        Sk.pre = "my-output";
+        Sk.configure({"output":outputHandler, "read":builtinRead});
+        try {
+           eval(Sk.importMainWithBody("<stdin>", false, prog));
+        }
+        catch(e) {
+          alert(e);
+        }
+      }
+    </script>
+  </body>
+</html>
diff --git a/src/lib/webgl/__init__.js b/src/lib/webgl/__init__.js
index 2b60c0f8f2dff96d57780a46c341c0d3e6023461..f2c88ba4e9f2fdb7e3942d16be992f603abbe709 100644
--- a/src/lib/webgl/__init__.js
+++ b/src/lib/webgl/__init__.js
@@ -1,389 +1,197 @@
 var $builtinmodule = function(name)
 {
-    var mod = {};
-
-    // todo; won't work compressed
-    mod.tp$name = "webgl";
-
-    //
-    // Setup code taken from 'tdl'. I tried to use more of it, but it's a bit
-    // broken.
-    //
-    var makeFailHTML = function(msg) {
-        return '' +
-            '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +
-            '<td align="center">' +
-            '<div style="display: table-cell; vertical-align: middle;">' +
-            '<div style="">' + msg + '</div>' +
-            '</div>' +
-            '</td></tr></table>';
-    };
-
-    var GET_A_WEBGL_BROWSER = '' +
-        'This page requires a browser that supports WebGL.<br/>' +
-        '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
-
-    var NEED_HARDWARE = '' +
-        "It doesn't appear your computer can support WebGL.<br/>" +
-        '<a href="http://get.webgl.org">Click here for more information.</a>';
+  var mod = {};
+
+  var makeFailHTML = function(msg) {
+    return '' +
+      '<table style="background-color: #8CE; width: 100%; height: 100%;"><tr>' +
+      '<td align="center">' +
+      '<div style="display: table-cell; vertical-align: middle;">' +
+      '<div style="">' + msg + '</div>' +
+      '</div>' +
+      '</td></tr></table>';
+  };
+
+  var GET_A_WEBGL_BROWSER = '' +
+    'This page requires a browser that supports WebGL.<br/>' +
+    '<a href="http://get.webgl.org">Click here to upgrade your browser.</a>';
+
+  var NEED_HARDWARE = '' +
+    "It doesn't appear your computer can support WebGL.<br/>" +
+    '<a href="http://get.webgl.org">Click here for more information.</a>';
   
-    var create3DContext = function(canvas) {
-        var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
-        var context = null;
-        for (var ii = 0; ii < names.length; ++ii) {
-            try {
-                context = canvas.getContext(names[ii]);
-            } catch(e) {}
-            if (context) {
-                break;
-            }
-        }
-        if (context) {
-            // Disallow selection by default. This keeps the cursor from changing to an
-            // I-beam when the user clicks and drags.  It's easier on the eyes.
-            function returnFalse() {
-                return false;
-            }
-
-            canvas.onselectstart = returnFalse;
-            canvas.onmousedown = returnFalse;
-        }
-        return context;
-    };
-
-    var setupWebGL = function(canvasContainerId, opt_canvas) {
-        var container = document.getElementById(canvasContainerId);
-        var context;
-        if (!opt_canvas) {
-            opt_canvas = container.getElementsByTagName("canvas")[0];
+  var create3DContext = function(canvas) {
+    var names = ["webgl", "experimental-webgl", "webkit-3d", "moz-webgl"];
+    var gl = null;
+    for (var ii = 0; ii < names.length; ++ii) {
+      try {
+        gl = canvas.getContext(names[ii]);
+      }
+      catch(e) {
+      }
+      if (gl) {
+          break;
+      }
+    }
+    if (gl) {
+      // Disallow selection by default. This keeps the cursor from changing to an
+      // I-beam when the user clicks and drags. It's easier on the eyes.
+      function returnFalse() {
+        return false;
+      }
+
+      canvas.onselectstart = returnFalse;
+      canvas.onmousedown = returnFalse;
+    }
+    return gl;
+  };
+
+  var setupWebGL = function(canvasContainerId, opt_canvas) {
+    var container = document.getElementById(canvasContainerId);
+    var context;
+    if (!opt_canvas) {
+      opt_canvas = container.getElementsByTagName("canvas")[0];
+    }
+    if (!opt_canvas) {
+        // this browser doesn't support the canvas tag at all. Not even 2d.
+      container.innerHTML = makeFailHTML(GET_A_WEBGL_BROWSER);
+      return;
+    }
+
+    var gl = create3DContext(opt_canvas);
+    if (!gl) {
+      // TODO(gman): fix to official way to detect that it's the user's machine, not the browser.
+      var browserStrings = navigator.userAgent.match(/(\w+\/.*? )/g);
+      var browsers = {};
+      try {
+        for (var b = 0; b < browserStrings.length; ++b) {
+          var parts = browserStrings[b].match(/(\w+)/g);
+          var bb = [];
+          for (var ii = 1; ii < parts.length; ++ii) {
+            bb.push(parseInt(parts[ii]));
+          }
+          browsers[parts[0]] = bb;
         }
-        if (!opt_canvas) {
-            // this browser doesn't support the canvas tag at all. Not even 2d.
-            container.innerHTML = makeFailHTML(
-                    GET_A_WEBGL_BROWSER);
-            return;
+      }
+      catch (e) {
+      }
+      if (browsers.Chrome &&
+           (browsers.Chrome[0] > 7 ||
+                 (browsers.Chrome[0] == 7 && browsers.Chrome[1] > 0) ||
+                 (browsers.Chrome[0] == 7 && browsers.Chrome[1] == 0 && browsers.Chrome[2] >= 521))) {
+        container.innerHTML = makeFailHTML(NEED_HARDWARE);
+      }
+      else {
+        container.innerHTML = makeFailHTML(GET_A_WEBGL_BROWSER);
+      }
+    }
+    return gl;
+  };
+
+  /**
+   * The Context encapsulates the underlying WebGL native JavaScript API.
+   */
+  mod.Context = Sk.misceval.buildClass(mod, function($gbl, $loc) {
+    $loc.__init__ = new Sk.builtin.func(
+      function(self, canvasid) {
+        var canvas = document.getElementById(canvasid.v);
+        var gl = setupWebGL(canvasid.v, canvas)
+        if (!gl) {
+          throw new Error("Your browser does not appear to support WebGL.");
         }
 
-        var context = create3DContext(opt_canvas);
-        if (!context) {
-            // TODO(gman): fix to official way to detect that it's the user's machine, not the browser.
-            var browserStrings = navigator.userAgent.match(/(\w+\/.*? )/g);
-            var browsers = {};
-            try {
-                for (var b = 0; b < browserStrings.length; ++b) {
-                    var parts = browserStrings[b].match(/(\w+)/g);
-                    var bb = [];
-                    for (var ii = 1; ii < parts.length; ++ii) {
-                        bb.push(parseInt(parts[ii]));
-                    }
-                    browsers[parts[0]] = bb;
-                }
-            } catch (e) {
-            }
-            if (browsers.Chrome &&
-                    (browsers.Chrome[0] > 7 ||
-                     (browsers.Chrome[0] == 7 && browsers.Chrome[1] > 0) ||
-                     (browsers.Chrome[0] == 7 && browsers.Chrome[1] == 0 && browsers.Chrome[2] >= 521))) {
-                container.innerHTML = makeFailHTML(
-                        NEED_HARDWARE);
-            } else {
-                container.innerHTML = makeFailHTML(
-                        GET_A_WEBGL_BROWSER);
+        self.gl = gl;
+
+        // Copy symbolic constants and functions from native WebGL, encapsulating where necessary.       
+        for (var k in gl.__proto__) {
+          if (typeof gl.__proto__[k] === 'number') {
+            Sk.abstr.objectSetItem(self['$d'], new Sk.builtin.str(k), gl.__proto__[k]);
+          }
+          else if (typeof gl.__proto__[k] === "function") {
+            switch(k) {
+              case 'bufferData': {
+              }
+              break;
+              case 'drawArrays': {
+              }
+              break;
+              case 'getAttribLocation': {
+              }
+              break;
+              case 'shaderSource': {
+              }
+              break;
+              case 'vertexAttribPointer': {
+              }
+              break;
+              default: {
+                (function(key) {
+                  Sk.abstr.objectSetItem(self['$d'], new Sk.builtin.str(k), new Sk.builtin.func(function() {
+                    var f = gl.__proto__[key];
+                    return f.apply(gl, arguments);
+                  }));
+                 }(k));
+              }
             }
+          }
         }
-        return context;
-    };
-
-    mod.Context = Sk.misceval.buildClass(mod, function($gbl, $loc)
-            {
-                $loc.__init__ = new Sk.builtin.func(function(self, canvasid)
-                    {
-                        var canvas = document.getElementById(canvasid.v);
-                        // NB: purposefully leak this to global because
-                        // everything wants it (esp. for constants it's a pain
-                        // to have to pass it to utility functions)
-                        /*var*/ gl = setupWebGL(canvasid.v, canvas)
-                        if (!gl)
-                            throw "couldn't get webgl context, unsupported browser?";
-
-                        self.gl = gl;
-                        // all (?) browsers that have webgl support
-                        // __proto__ too so we cheese out and just rip
-                        // them out of there rather than manually
-                        // enumerating the entire webgl api. it wouldn't
-                        // be too difficult to do it "properly", just
-                        // long.
-                        for (var k in gl.__proto__)
-                        {
-                            if (typeof gl.__proto__[k] === "number")
-                            {
-                                Sk.abstr.objectSetItem(self['$d'], new Sk.builtin.str(k), gl.__proto__[k]);
-                            }
-                            else if (typeof gl.__proto__[k] === "function")
-                            {
-                                (function(key) {
-                                Sk.abstr.objectSetItem(self['$d'], new Sk.builtin.str(k), new Sk.builtin.func(function()
-                                    {
-                                        var f = gl.__proto__[key];
-                                        // todo; assuming only basic
-                                        // type returns?
-                                        return f.apply(gl, arguments);
-                                    }));
-                                }(k));
-                            }
-                        }
-
-                        console.log("gl initialized", gl, canvas, canvas.width, canvas.height);
-
-                        // set to cornflower so we know we're init'd at least
-                        gl.clearColor(100/255.0,149/255.0,237/255.0,1);
-                        gl.bindFramebuffer(gl.FRAMEBUFFER, null);
-                        gl.viewport(0, 0, canvas.width, canvas.height);
-                        gl.clear(gl.COLOR_BUFFER_BIT);
-                        gl.flush();
-                    });
-
-                $loc.tp$getattr = Sk.builtin.object.prototype.GenericGetAttr;
-
-                $loc.setDrawFunc = new Sk.builtin.func(function(self, func)
-                        {
-                            var startTime = (new Date()).getTime();
-                            var intervalId = setInterval(function() {
-                                    Sk.misceval.callsim(func, self, (new Date()).getTime() - startTime);
-                                    if (goog.global.shutdownGLContext)
-                                    {
-                                        clearInterval(intervalId);
-                                        console.log("gl draw function shutting down");
-                                        return;
-                                    }
-                                }, 1000.0 / 60.0);
-                                
-                        });
-            },
-            'Context', []);
-
-    mod.Shader = Sk.misceval.buildClass(mod, function($gbl, $loc)
-            {
-                $loc.__init__ = new Sk.builtin.func(function(self, gl, vertex, fragment)
-                        {
-                            self.gl = gl.gl;
-                            var gl = self.gl;
-                            self.program = gl.createProgram();
-                            var vs = gl.createShader(gl.VERTEX_SHADER);
-                            gl.shaderSource(vs, vertex.v);
-                            gl.compileShader(vs);
-                            if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))
-                            {
-                                console.log(gl.getShaderInfoLog(vs));
-                                throw new Sk.builtin.SyntaxError("Error compiling vertex shader:" + gl.getShaderInfoLog(vs));
-                            }
-                            gl.attachShader(self.program, vs);
-                            gl.deleteShader(vs);
-                            
-                            var fs = gl.createShader(gl.FRAGMENT_SHADER);
-                            gl.shaderSource(fs, fragment.v);
-                            gl.compileShader(fs);
-                            if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))
-                            {
-                                console.log(gl.getShaderInfoLog(fs));
-                                throw new Sk.builtin.SyntaxError("Error compiling fragment shader:" + gl.getShaderInfoLog(fs));
-                            }
-                            gl.attachShader(self.program, fs);
-                            gl.deleteShader(fs);
-
-                            gl.linkProgram(self.program);
-                            gl.useProgram(self.program);
-
-
-                            //
-                            //
-                            // Some more init code from 'tdl' (slightly
-                            // tweaked)
-                            //
-                            //
-
-                            var endsWith = function(haystack, needle) {
-                                return haystack.substr(haystack.length - needle.length) === needle;
-                            };
-
-                            // Look up attribs.
-                            var attribs = {
-                            };
-                            // Also make a plain table of the locs.
-                            var attribLocs = {
-                            };
-
-                            function createAttribSetter(info, index) {
-                                if (info.size != 1) {
-                                    throw("arrays of attribs not handled");
-                                }
-                                return function(b) {
-                                    gl.bindBuffer(gl.ARRAY_BUFFER, b.buffer());
-                                    gl.enableVertexAttribArray(index);
-                                    gl.vertexAttribPointer(
-                                            index, b.numComponents(), b.type(), false, b.stride(), b.offset());
-                                };
-                            }
-
-                            var numAttribs = gl.getProgramParameter(self.program, gl.ACTIVE_ATTRIBUTES);
-                            for (var ii = 0; ii < numAttribs; ++ii) {
-                                var info = gl.getActiveAttrib(self.program, ii);
-                                name = info.name;
-                                if (endsWith(name, "[0]")) {
-                                    name = name.substr(0, name.length - 3);
-                                }
-                                var index = gl.getAttribLocation(self.program, info.name);
-                                attribs[name] = createAttribSetter(info, index);
-                                attribLocs[name] = index
-                            }
-
-                            // Look up uniforms
-                            var numUniforms = gl.getProgramParameter(self.program, gl.ACTIVE_UNIFORMS);
-                            var uniforms = {
-                            };
-
-                            function createUniformSetter(info) {
-                                var loc = gl.getUniformLocation(self.program, info.name);
-                                var type = info.type;
-                                if (info.size > 1 && endsWith(info.name, "[0]")) {
-                                    // It's an array.
-                                    if (type == gl.FLOAT)
-                                        return function(v) { gl.uniform1fv(loc, v); };
-                                    if (type == gl.FLOAT_VEC2)
-                                        return function(v) { gl.uniform2fv(loc, v); };
-                                    if (type == gl.FLOAT_VEC3)
-                                        return function(v) { gl.uniform3fv(loc, v); };
-                                    if (type == gl.FLOAT_VEC4)
-                                        return function(v) { gl.uniform4fv(loc, v); };
-                                    if (type == gl.INT)
-                                        return function(v) { gl.uniform1iv(loc, v); };
-                                    if (type == gl.INT_VEC2)
-                                        return function(v) { gl.uniform2iv(loc, v); };
-                                    if (type == gl.INT_VEC3)
-                                        return function(v) { gl.uniform3iv(loc, v); };
-                                    if (type == gl.INT_VEC4)
-                                        return function(v) { gl.uniform4iv(loc, v); };
-                                    if (type == gl.BOOL)
-                                        return function(v) { gl.uniform1iv(loc, v); };
-                                    if (type == gl.BOOL_VEC2)
-                                        return function(v) { gl.uniform2iv(loc, v); };
-                                    if (type == gl.BOOL_VEC3)
-                                        return function(v) { gl.uniform3iv(loc, v); };
-                                    if (type == gl.BOOL_VEC4)
-                                        return function(v) { gl.uniform4iv(loc, v); };
-                                    if (type == gl.FLOAT_MAT2)
-                                        return function(v) { gl.uniformMatrix2fv(loc, false, v); };
-                                    if (type == gl.FLOAT_MAT3)
-                                        return function(v) { gl.uniformMatrix3fv(loc, false, v); };
-                                    if (type == gl.FLOAT_MAT4)
-                                        return function(v) { gl.uniformMatrix4fv(loc, false, v); };
-                                    if (type == gl.SAMPLER_2D)
-                                        return function(v) { gl.uniform1iv(loc, v); };
-                                    if (type == gl.SAMPLER_CUBE_MAP)
-                                        return function(v) { gl.uniform1iv(loc, v); };
-                                    throw ("unknown type: 0x" + type.toString(16));
-                                } else {
-                                    if (type == gl.FLOAT)
-                                        return function(v) { gl.uniform1f(loc, v); };
-                                    if (type == gl.FLOAT_VEC2)
-                                        return function(v) { gl.uniform2fv(loc, v); };
-                                    if (type == gl.FLOAT_VEC3)
-                                        return function(v) { gl.uniform3fv(loc, v); };
-                                    if (type == gl.FLOAT_VEC4)
-                                        return function(v) { gl.uniform4fv(loc, v); };
-                                    if (type == gl.INT)
-                                        return function(v) { gl.uniform1i(loc, v); };
-                                    if (type == gl.INT_VEC2)
-                                        return function(v) { gl.uniform2iv(loc, v); };
-                                    if (type == gl.INT_VEC3)
-                                        return function(v) { gl.uniform3iv(loc, v); };
-                                    if (type == gl.INT_VEC4)
-                                        return function(v) { gl.uniform4iv(loc, v); };
-                                    if (type == gl.BOOL)
-                                        return function(v) { gl.uniform1i(loc, v); };
-                                    if (type == gl.BOOL_VEC2)
-                                        return function(v) { gl.uniform2iv(loc, v); };
-                                    if (type == gl.BOOL_VEC3)
-                                        return function(v) { gl.uniform3iv(loc, v); };
-                                    if (type == gl.BOOL_VEC4)
-                                        return function(v) { gl.uniform4iv(loc, v); };
-                                    if (type == gl.FLOAT_MAT2)
-                                        return function(v) { gl.uniformMatrix2fv(loc, false, v); };
-                                    if (type == gl.FLOAT_MAT3)
-                                        return function(v) { gl.uniformMatrix3fv(loc, false, v); };
-                                    if (type == gl.FLOAT_MAT4)
-                                        return function(v) { gl.uniformMatrix4fv(loc, false, v); };
-                                    if (type == gl.SAMPLER_2D)
-                                        return function(v) { gl.uniform1i(loc, v); };
-                                    if (type == gl.SAMPLER_CUBE)
-                                        return function(v) { gl.uniform1i(loc, v); };
-                                    throw ("unknown type: 0x" + type.toString(16));
-                                }
-                            }
-
-                            for (var ii = 0; ii < numUniforms; ++ii) {
-                                var info = gl.getActiveUniform(self.program, ii);
-                                name = info.name;
-                                if (endsWith(name, "[0]")) {
-                                    name = name.substr(0, name.length - 3);
-                                }
-                                uniforms[name] = createUniformSetter(info);
-                            }
-
-                            self.attrib = attribs;
-                            self.attribLoc = attribLocs;
-                            self.uniform = uniforms;
-                        });
-
-                $loc.setUniform = new Sk.builtin.func(function(self, uniform, value)
-                        {
-                            var func = self.uniform[uniform.v];
-                            if (func)
-                            {
-                                //console.log("SET UNI:", uniform.v, value);
-                                func(Sk.ffi.remapToJs(value));
-                            }
-                        });
-
-                $loc.setUniform$impl = function(self, uniform, value)
-                        {
-                            var func = self.uniform[uniform];
-                            if (func)
-                            {
-                                //console.log("SET UNI:", uniform, value);
-                                func(value);
-                            }
-                        };
-
-                $loc.use = new Sk.builtin.func(function(self)
-                        {
-                            self.gl.useProgram(self.program);
-                        });
-            },
-            'Shader', []);
-
-
-    mod.Float32Array = Sk.misceval.buildClass(mod, function($gbl, $loc)
-            {
-                $loc.__init__ = new Sk.builtin.func(function(self, data)
-                        {
-                            if (typeof data === "number")
-                                self.v = new Float32Array(data);
-                            else
-                                self.v = new Float32Array(Sk.ffi.remapToJs(data));
-                        });
-
-                $loc.__repr__ = new Sk.builtin.func(function(self)
-                    {
-                        var copy = [];
-                        for (var i = 0; i < self.v.length; ++i)
-                            copy.push(self.v[i]);
-                        return new Sk.builtin.str("["+copy.join(', ')+"]");
-                    });
-
-            },
-            'Float32Array', []);
-
 
-    return mod;
-};
+        gl.clearColor(100.0/255.0, 149.0/255.0, 237.0/255.0, 1.0);
+        gl.clear(gl.COLOR_BUFFER_BIT);
+      }
+    );
+
+    $loc.tp$getattr = Sk.builtin.object.prototype.GenericGetAttr;
+
+    $loc.bufferData = new Sk.builtin.func(
+      function(self, target, data, usage) {
+        self.gl.bufferData(target, data.v, usage);
+      }
+    );
+
+    $loc.getAttribLocation = new Sk.builtin.func(
+      function(self, program, name) {
+        return self.gl.getAttribLocation(program, name.v);
+      }
+    );
+
+    $loc.shaderSource = new Sk.builtin.func(
+      function(self, shader, src) {
+        self.gl.shaderSource(shader, src.v);
+      }
+    );
+
+    $loc.drawArrays = new Sk.builtin.func(
+      function(self, mode, first, count) {
+        self.gl.drawArrays(Sk.builtin.asnum$(mode), Sk.builtin.asnum$(first), Sk.builtin.asnum$(count));
+      }
+    );
+    
+    $loc.vertexAttribPointer = new Sk.builtin.func(
+      function(self, index, size, type, normalized, stride, dunno) {
+        self.gl.vertexAttribPointer(index, Sk.builtin.asnum$(size), Sk.builtin.asnum$(type), normalized, Sk.builtin.asnum$(stride), Sk.builtin.asnum$(dunno));
+      }
+    );
+  }, 'Context', []);
+
+  mod.Float32Array = Sk.misceval.buildClass(mod, function($gbl, $loc) {
+    $loc.__init__ = new Sk.builtin.func(function(self, data) {
+      if (typeof data === "number") {
+        self.v = new Float32Array(data);
+      }
+      else {
+        self.v = new Float32Array(Sk.ffi.remapToJs(data));
+      }
+    });
+
+    $loc.__repr__ = new Sk.builtin.func(function(self) {
+      var copy = [];
+      for (var i = 0; i < self.v.length; ++i) {
+        copy.push(self.v[i]);
+      }
+      return new Sk.builtin.str("[" + copy.join(', ') + "]");
+     });
+  }, 'Float32Array', []);
+
+  return mod;
+};
\ No newline at end of file