diff --git a/Cargo.toml b/Cargo.toml
index 3c785576..2ce49eb4 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -78,6 +78,7 @@ members = [
"examples/smorgasboard",
"examples/wasm-in-wasm",
"examples/webaudio",
+ "examples/webgl",
"tests/no-std",
]
diff --git a/examples/webgl/.gitignore b/examples/webgl/.gitignore
new file mode 100755
index 00000000..fc819eeb
--- /dev/null
+++ b/examples/webgl/.gitignore
@@ -0,0 +1,4 @@
+package-lock.json
+wasm_bindgen_webgl_demo.js
+wasm_bindgen_webgl_demo_bg.js
+wasm_bindgen_webgl_demo_bg.wasm
diff --git a/examples/webgl/Cargo.toml b/examples/webgl/Cargo.toml
new file mode 100755
index 00000000..7dd6581f
--- /dev/null
+++ b/examples/webgl/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "wasm-bindgen-webgl-demo"
+version = "0.1.0"
+authors = ["The wasm-bindgen Developers"]
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+js-sys = { path = "../../crates/js-sys" }
+wasm-bindgen = { path = "../.." }
+
+[dependencies.web-sys]
+path = "../../crates/web-sys"
+features = [
+ 'Document',
+ 'Element',
+ 'HtmlCanvasElement',
+ 'WebGlBuffer',
+ 'WebGlRenderingContext',
+ 'WebGlProgram',
+ 'WebGlShader',
+ 'Window',
+]
diff --git a/examples/webgl/README.md b/examples/webgl/README.md
new file mode 100755
index 00000000..b31d41c7
--- /dev/null
+++ b/examples/webgl/README.md
@@ -0,0 +1,15 @@
+# WebGL Example
+
+This directory is an example of using the `web-sys` crate to interact with
+a WebGL context.
+
+You can build and run the example with:
+
+```
+$ ./build.sh
+```
+
+(or running the commands on Windows manually)
+
+and then opening up `http://localhost:8080/` in a web browser should show a
+nice triangle.
diff --git a/examples/webgl/build.sh b/examples/webgl/build.sh
new file mode 100755
index 00000000..55a54b0e
--- /dev/null
+++ b/examples/webgl/build.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+# For more coments about what's going on here, see the `hello_world` example
+
+set -ex
+cd "$(dirname $0)"
+
+cargo +nightly build --target wasm32-unknown-unknown
+
+cargo +nightly run --manifest-path ../../crates/cli/Cargo.toml \
+ --bin wasm-bindgen -- \
+ ../../target/wasm32-unknown-unknown/debug/wasm_bindgen_webgl_demo.wasm --out-dir .
+
+npm install
+npm run serve
diff --git a/examples/webgl/index.html b/examples/webgl/index.html
new file mode 100755
index 00000000..c13b999e
--- /dev/null
+++ b/examples/webgl/index.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/examples/webgl/index.js b/examples/webgl/index.js
new file mode 100755
index 00000000..cb5f7a9a
--- /dev/null
+++ b/examples/webgl/index.js
@@ -0,0 +1,5 @@
+// For more comments about what's going on here, check out the `hello_world`
+// example.
+import('./wasm_bindgen_webgl_demo').then(webgl => {
+ webgl.draw();
+});
diff --git a/examples/webgl/package.json b/examples/webgl/package.json
new file mode 100755
index 00000000..176a69a4
--- /dev/null
+++ b/examples/webgl/package.json
@@ -0,0 +1,11 @@
+{
+ "scripts": {
+ "serve": "webpack-dev-server"
+ },
+ "devDependencies": {
+ "html-webpack-plugin": "^3.2.0",
+ "webpack": "^4.11.1",
+ "webpack-cli": "^2.0.10",
+ "webpack-dev-server": "^3.1.0"
+ }
+}
diff --git a/examples/webgl/src/lib.rs b/examples/webgl/src/lib.rs
new file mode 100755
index 00000000..d584f71d
--- /dev/null
+++ b/examples/webgl/src/lib.rs
@@ -0,0 +1,121 @@
+extern crate js_sys;
+extern crate wasm_bindgen;
+extern crate web_sys;
+
+use wasm_bindgen::prelude::*;
+use wasm_bindgen::JsCast;
+use web_sys::{WebGlProgram, WebGlRenderingContext, WebGlShader};
+
+#[wasm_bindgen]
+pub fn draw() {
+ let document = web_sys::Window::document().unwrap();
+ let canvas = document.get_element_by_id("canvas").unwrap();
+ let canvas: web_sys::HtmlCanvasElement = canvas
+ .dyn_into::()
+ .map_err(|_| ())
+ .unwrap();
+
+ let context = canvas
+ .get_context("webgl")
+ .unwrap()
+ .unwrap()
+ .dyn_into::()
+ .unwrap();
+
+ let vert_shader = compile_shader(
+ &context,
+ WebGlRenderingContext::VERTEX_SHADER,
+ r#"
+ attribute vec4 position;
+ void main() {
+ gl_Position = position;
+ }
+ "#,
+ ).unwrap();
+ let frag_shader = compile_shader(
+ &context,
+ WebGlRenderingContext::FRAGMENT_SHADER,
+ r#"
+ void main() {
+ gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
+ }
+ "#,
+ ).unwrap();
+ let program = link_program(&context, [vert_shader, frag_shader].iter()).unwrap();
+ context.use_program(Some(&program));
+
+ let vertices = [-0.7, -0.7, 0.0, 0.7, -0.7, 0.0, 0.0, 0.7, 0.0];
+ let vert_array = js_sys::Float32Array::new(&wasm_bindgen::JsValue::from(vertices.len() as u32));
+ for (i, f) in vertices.iter().enumerate() {
+ vert_array.fill(*f, i as u32, (i + 1) as u32);
+ }
+
+ let buffer = context.create_buffer().unwrap();
+ context.bind_buffer(WebGlRenderingContext::ARRAY_BUFFER, Some(&buffer));
+ context.buffer_data_with_opt_array_buffer(
+ WebGlRenderingContext::ARRAY_BUFFER,
+ Some(&vert_array.buffer()),
+ WebGlRenderingContext::STATIC_DRAW,
+ );
+ context.vertex_attrib_pointer_with_i32(0,
+ 3,
+ WebGlRenderingContext::FLOAT,
+ false,
+ 0,
+ 0);
+ context.enable_vertex_attrib_array(0);
+
+ context.clear_color(0.0, 0.0, 0.0, 1.0);
+ context.clear(WebGlRenderingContext::COLOR_BUFFER_BIT);
+
+ context.draw_arrays(WebGlRenderingContext::TRIANGLES, 0, (vertices.len() / 3) as i32);
+}
+
+pub fn compile_shader(
+ context: &WebGlRenderingContext,
+ shader_type: u32,
+ source: &str,
+) -> Result {
+ let shader = context
+ .create_shader(shader_type)
+ .ok_or_else(|| String::from("Unable to create shader object"))?;
+ context.shader_source(&shader, source);
+ context.compile_shader(&shader);
+
+ if context
+ .get_shader_parameter(&shader, WebGlRenderingContext::COMPILE_STATUS)
+ .as_bool()
+ .unwrap_or(false)
+ {
+ Ok(shader)
+ } else {
+ Err(context
+ .get_shader_info_log(&shader)
+ .unwrap_or_else(|| "Unknown error creating shader".into()))
+ }
+}
+
+pub fn link_program<'a, T: IntoIterator- >(
+ context: &WebGlRenderingContext,
+ shaders: T,
+) -> Result {
+ let program = context
+ .create_program()
+ .ok_or_else(|| String::from("Unable to create shader object"))?;
+ for shader in shaders {
+ context.attach_shader(&program, shader)
+ }
+ context.link_program(&program);
+
+ if context
+ .get_program_parameter(&program, WebGlRenderingContext::LINK_STATUS)
+ .as_bool()
+ .unwrap_or(false)
+ {
+ Ok(program)
+ } else {
+ Err(context
+ .get_program_info_log(&program)
+ .unwrap_or_else(|| "Unknown error creating program object".into()))
+ }
+}
diff --git a/examples/webgl/webpack.config.js b/examples/webgl/webpack.config.js
new file mode 100755
index 00000000..453a1a59
--- /dev/null
+++ b/examples/webgl/webpack.config.js
@@ -0,0 +1,16 @@
+const path = require('path');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+
+module.exports = {
+ entry: './index.js',
+ output: {
+ path: path.resolve(__dirname, 'dist'),
+ filename: 'index.js',
+ },
+ plugins: [
+ new HtmlWebpackPlugin({
+ template: "index.html"
+ })
+ ],
+ mode: 'development'
+};
diff --git a/guide/src/SUMMARY.md b/guide/src/SUMMARY.md
index 97069f78..8bf8d337 100644
--- a/guide/src/SUMMARY.md
+++ b/guide/src/SUMMARY.md
@@ -62,6 +62,7 @@
- [The `fetch` API](./web-sys/examples/fetch.md)
- [2D Canvas](./web-sys/examples/2d-canvas.md)
- [WebAudio](./web-sys/examples/web-audio.md)
+ - [WebGL](./web-sys/examples/webgl.md)
- [A Simple Paint Program](./web-sys/examples/paint.md)
--------------------------------------------------------------------------------
diff --git a/guide/src/web-sys/examples/webgl.md b/guide/src/web-sys/examples/webgl.md
new file mode 100644
index 00000000..38a886f8
--- /dev/null
+++ b/guide/src/web-sys/examples/webgl.md
@@ -0,0 +1,25 @@
+# 2D Canvas
+
+This example draws a triangle to the screen using the WebGL API.
+
+[See the full source at
+`wasm-bindgen/examples/webgl`.](https://github.com/rustwasm/wasm-bindgen/tree/master/examples/webgl)
+
+## `Cargo.toml`
+
+The `Cargo.toml` enables features necessary to obtain and use a WebGL
+rendering context.
+
+```toml
+{{#include ../../../../examples/webgl/Cargo.toml}}
+```
+
+## `src/lib.rs`
+
+This source file handles all of the necessary logic to obtain a rendering
+context, compile shaders, fill a buffer with vertex coordinates, and draw a
+triangle to the screen.
+
+```rust
+{{#include ../../../../examples/webgl/src/lib.rs}}
+```