You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
learn-wgpu/beginner/tutorial1-window/index.html

154 lines
54 KiB
HTML

<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Dependencies and the window | Learn Wgpu</title>
<meta name="generator" content="VuePress 1.9.10">
<meta name="description" content="">
<link rel="preload" href="/learn-wgpu/assets/css/0.styles.81cb5453.css" as="style"><link rel="preload" href="/learn-wgpu/assets/js/app.9afc5d83.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/2.2ef7287a.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/1.eaeeb819.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/55.79d255a9.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/33.c548d7f9.js" as="script"><link rel="preload" href="/learn-wgpu/assets/js/37.5ecf7ce2.js" as="script"><link rel="prefetch" href="/learn-wgpu/assets/js/10.baf5d1fe.js"><link rel="prefetch" href="/learn-wgpu/assets/js/11.b8633c49.js"><link rel="prefetch" href="/learn-wgpu/assets/js/12.0b8835f1.js"><link rel="prefetch" href="/learn-wgpu/assets/js/13.af1bbe85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/14.626c7cb3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/15.5a8ea302.js"><link rel="prefetch" href="/learn-wgpu/assets/js/16.f4e8226b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/17.ea2d3b52.js"><link rel="prefetch" href="/learn-wgpu/assets/js/18.4eb59bb5.js"><link rel="prefetch" href="/learn-wgpu/assets/js/19.48960e96.js"><link rel="prefetch" href="/learn-wgpu/assets/js/20.a01dc53f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/21.5e81f33c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/22.caf73498.js"><link rel="prefetch" href="/learn-wgpu/assets/js/23.5ef2ce85.js"><link rel="prefetch" href="/learn-wgpu/assets/js/24.9ed2104b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/25.1676676b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/26.60954390.js"><link rel="prefetch" href="/learn-wgpu/assets/js/27.ba9ff2c4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/28.d9dcc3ca.js"><link rel="prefetch" href="/learn-wgpu/assets/js/29.ea2d6bbf.js"><link rel="prefetch" href="/learn-wgpu/assets/js/3.80d94795.js"><link rel="prefetch" href="/learn-wgpu/assets/js/30.f08bd92d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/31.74bc1dea.js"><link rel="prefetch" href="/learn-wgpu/assets/js/32.e6627282.js"><link rel="prefetch" href="/learn-wgpu/assets/js/34.0fe8e5e4.js"><link rel="prefetch" href="/learn-wgpu/assets/js/35.7c607f94.js"><link rel="prefetch" href="/learn-wgpu/assets/js/36.6e9002ae.js"><link rel="prefetch" href="/learn-wgpu/assets/js/38.b0253733.js"><link rel="prefetch" href="/learn-wgpu/assets/js/39.73123b03.js"><link rel="prefetch" href="/learn-wgpu/assets/js/4.ff267fdb.js"><link rel="prefetch" href="/learn-wgpu/assets/js/40.30864a0f.js"><link rel="prefetch" href="/learn-wgpu/assets/js/41.b9820613.js"><link rel="prefetch" href="/learn-wgpu/assets/js/42.4caac867.js"><link rel="prefetch" href="/learn-wgpu/assets/js/43.991fa7d2.js"><link rel="prefetch" href="/learn-wgpu/assets/js/44.89508e56.js"><link rel="prefetch" href="/learn-wgpu/assets/js/45.2ea5b108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/46.bb26f2fc.js"><link rel="prefetch" href="/learn-wgpu/assets/js/47.52c91180.js"><link rel="prefetch" href="/learn-wgpu/assets/js/48.7d70df25.js"><link rel="prefetch" href="/learn-wgpu/assets/js/49.e307b357.js"><link rel="prefetch" href="/learn-wgpu/assets/js/5.250d79d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/50.05fd19ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/51.820d6108.js"><link rel="prefetch" href="/learn-wgpu/assets/js/52.09f16d08.js"><link rel="prefetch" href="/learn-wgpu/assets/js/53.53394024.js"><link rel="prefetch" href="/learn-wgpu/assets/js/54.daee63ce.js"><link rel="prefetch" href="/learn-wgpu/assets/js/56.e9c45fb7.js"><link rel="prefetch" href="/learn-wgpu/assets/js/57.9cdfcb79.js"><link rel="prefetch" href="/learn-wgpu/assets/js/58.35b75a7b.js"><link rel="prefetch" href="/learn-wgpu/assets/js/59.5dd82339.js"><link rel="prefetch" href="/learn-wgpu/assets/js/60.1ced8124.js"><link rel="prefetch" href="/learn-wgpu/assets/js/61.f10516d3.js"><link rel="prefetch" href="/learn-wgpu/assets/js/62.fc721fd9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/63.68526f40.js"><link rel="prefetch" href="/learn-wgpu/assets/js/64.5fd53e01.js"><link rel="prefetch" href="/learn-wgpu/assets/js/65.5151244c.js"><link rel="prefetch" href="/learn-wgpu/assets/js/66.a136cd48.js"><link rel="prefetch" href="/learn-wgpu/assets/js/67.cf780dc9.js"><link rel="prefetch" href="/learn-wgpu/assets/js/68.d785413d.js"><link rel="prefetch" href="/learn-wgpu/assets/js/8.2c0d831a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/9.985bc61a.js"><link rel="prefetch" href="/learn-wgpu/assets/js/vendors~docsearch.efa6f8ef.js">
<link rel="stylesheet" href="/learn-wgpu/assets/css/0.styles.81cb5453.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container"><header class="navbar"><div class="inner"><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/learn-wgpu/" class="home-link router-link-active"><!----> <span class="site-name">Learn Wgpu</span></a> <div class="links"><!----> <div class="search-box"><input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div></div></div></header> <div class="sidebar-mask"></div> <div class="docs-layout"><aside class="sidebar"><!----> <ul class="sidebar-links"><li><a href="/learn-wgpu/" aria-current="page" class="sidebar-link">Introduction</a></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading open"><span>Beginner</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/beginner/tutorial1-window/" aria-current="page" class="active sidebar-link">Dependencies and the window</a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#boring-i-know" class="sidebar-link">Boring, I know</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#what-crates-are-we-using" class="sidebar-link">What crates are we using?</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#using-rust-s-new-resolver" class="sidebar-link">Using Rust's new resolver</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#env-logger" class="sidebar-link">env_logger</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#create-a-new-project" class="sidebar-link">Create a new project</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#the-code" class="sidebar-link">The code</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#added-support-for-the-web" class="sidebar-link">Added support for the web</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#web-assembly" class="sidebar-link">Web Assembly</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#more-code" class="sidebar-link">More code</a></li><li class="sidebar-sub-header"><a href="/learn-wgpu/beginner/tutorial1-window/#wasm-pack" class="sidebar-link">Wasm Pack</a></li></ul></li><li><a href="/learn-wgpu/beginner/tutorial2-surface/" class="sidebar-link">The Surface</a></li><li><a href="/learn-wgpu/beginner/tutorial3-pipeline/" class="sidebar-link">The Pipeline</a></li><li><a href="/learn-wgpu/beginner/tutorial4-buffer/" class="sidebar-link">Buffers and Indices</a></li><li><a href="/learn-wgpu/beginner/tutorial5-textures/" class="sidebar-link">Textures and bind groups</a></li><li><a href="/learn-wgpu/beginner/tutorial6-uniforms/" class="sidebar-link">Uniform buffers and a 3d camera</a></li><li><a href="/learn-wgpu/beginner/tutorial7-instancing/" class="sidebar-link">Instancing</a></li><li><a href="/learn-wgpu/beginner/tutorial8-depth/" class="sidebar-link">The Depth Buffer</a></li><li><a href="/learn-wgpu/beginner/tutorial9-models/" class="sidebar-link">Model Loading</a></li></ul></section></li><li><section class="sidebar-group depth-0"><p class="sidebar-heading"><span>Intermediate</span> <!----></p> <ul class="sidebar-links sidebar-group-items"><li><a href="/learn-wgpu/intermediate/tutorial10-lighting/" class="sidebar-link">Working with Lights</a></li><li><a href="/learn-wgpu/intermediate/tutorial11-normals/" class="sidebar-link">Normal Mapping</a></li><li><a href="/learn-wgpu/intermediate/tutorial12-camera/" class="sidebar-link">A Better Camera</a></li><li><a href="/learn-wgpu/intermediate/tutorial13-hdr/" class="sidebar-link">High Dynamic Range Rendering</a></li></ul></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>Showcase</span> <span class="arrow right"></span></p> <!----></section></li><li><section class="sidebar-group collapsable depth-0"><p class="sidebar-heading"><span>News</span> <span class="arrow right"></span></p> <!----></section></li></ul> </aside> <main class="page"> <div class="theme-default-content content__default"><h1 id="dependencies-and-the-window"><a href="#dependencies-and-the-window" class="header-anchor">#</a> Dependencies and the window</h1> <h2 id="boring-i-know"><a href="#boring-i-know" class="header-anchor">#</a> Boring, I know</h2> <p>Some of you reading this are very experienced with opening up windows in Rust and probably have your favorite windowing library, but this guide is designed for everybody, so it's something that we need to cover. Luckily, you don't need to read this if you know what you're doing. One thing that you do need to know is that whatever windowing solution you use needs to support the <a href="https://github.com/rust-windowing/raw-window-handle" target="_blank" rel="noopener noreferrer">raw-window-handle<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> crate.</p> <h2 id="what-crates-are-we-using"><a href="#what-crates-are-we-using" class="header-anchor">#</a> What crates are we using?</h2> <p>For the beginner stuff, we're going to keep things very simple. We'll add things as we go, but I've listed the relevant <code>Cargo.toml</code> bits below.</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span>
<span class="token key property">winit</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.28&quot;</span>
<span class="token key property">env_logger</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.10&quot;</span>
<span class="token key property">log</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.4&quot;</span>
<span class="token key property">wgpu</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.18&quot;</span>
</code></pre></div><h2 id="using-rust-s-new-resolver"><a href="#using-rust-s-new-resolver" class="header-anchor">#</a> Using Rust's new resolver</h2> <p>As of version 0.10, wgpu requires Cargo's <a href="https://doc.rust-lang.org/cargo/reference/resolver.html#feature-resolver-version-2" target="_blank" rel="noopener noreferrer">newest feature resolver<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>, which is the default in the 2021 edition (any new project started with Rust version 1.56.0 or newer). However, if you are still using the 2018 edition, you must include <code>resolver = &quot;2&quot;</code> in either the <code>[package]</code> section of <code>Cargo.toml</code> if you are working on a single crate or the <code>[workspace]</code> section of the root <code>Cargo.toml</code> in a workspace.</p> <h2 id="env-logger"><a href="#env-logger" class="header-anchor">#</a> env_logger</h2> <p>It is very important to enable logging via <code>env_logger::init();</code>.
When wgpu hits any error it panics with a generic message, while logging the real error via the log crate.
This means if you don't include <code>env_logger::init()</code>, wgpu will fail silently, leaving you very confused!<br>
(This has been done in the code below)</p> <h2 id="create-a-new-project"><a href="#create-a-new-project" class="header-anchor">#</a> Create a new project</h2> <p>run <code>cargo new project_name</code> where project_name is the name of the project.<br>
(In the example below, I have used 'tutorial1_window')</p> <h2 id="the-code"><a href="#the-code" class="header-anchor">#</a> The code</h2> <p>There's not much going on here yet, so I'm just going to post the code in full. Just paste this into your <code>lib.rs</code> or equivalent.</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span></span><span class="token punctuation">{</span>
<span class="token namespace">event<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">,</span>
<span class="token namespace">event_loop<span class="token punctuation">::</span></span><span class="token punctuation">{</span><span class="token class-name">ControlFlow</span><span class="token punctuation">,</span> <span class="token class-name">EventLoop</span><span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token namespace">window<span class="token punctuation">::</span></span><span class="token class-name">WindowBuilder</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token namespace">env_logger<span class="token punctuation">::</span></span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> event_loop <span class="token operator">=</span> <span class="token class-name">EventLoop</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> window <span class="token operator">=</span> <span class="token class-name">WindowBuilder</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">build</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>event_loop<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">unwrap</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
event_loop<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token keyword">move</span> <span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>event<span class="token punctuation">,</span> _<span class="token punctuation">,</span> control_flow<span class="token closure-punctuation punctuation">|</span></span> <span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token class-name">Event</span><span class="token punctuation">::</span><span class="token class-name">WindowEvent</span> <span class="token punctuation">{</span>
<span class="token keyword">ref</span> event<span class="token punctuation">,</span>
window_id<span class="token punctuation">,</span>
<span class="token punctuation">}</span> <span class="token keyword">if</span> window_id <span class="token operator">==</span> window<span class="token punctuation">.</span><span class="token function">id</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token keyword">match</span> event <span class="token punctuation">{</span>
<span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">CloseRequested</span>
<span class="token operator">|</span> <span class="token class-name">WindowEvent</span><span class="token punctuation">::</span><span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
input<span class="token punctuation">:</span>
<span class="token class-name">KeyboardInput</span> <span class="token punctuation">{</span>
state<span class="token punctuation">:</span> <span class="token class-name">ElementState</span><span class="token punctuation">::</span><span class="token class-name">Pressed</span><span class="token punctuation">,</span>
virtual_keycode<span class="token punctuation">:</span> <span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token class-name">VirtualKeyCode</span><span class="token punctuation">::</span><span class="token class-name">Escape</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">..</span>
<span class="token punctuation">}</span> <span class="token operator">=&gt;</span> <span class="token operator">*</span>control_flow <span class="token operator">=</span> <span class="token class-name">ControlFlow</span><span class="token punctuation">::</span><span class="token class-name">Exit</span><span class="token punctuation">,</span>
_ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
_ <span class="token operator">=&gt;</span> <span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>All this does is create a window and keep it open until the user closes it or presses escape. Next, we'll need a <code>main.rs</code> to run the code. It's quite simple, it just imports <code>run()</code> and, well, runs it!</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token keyword">use</span> <span class="token namespace">tutorial1_window<span class="token punctuation">::</span></span>run<span class="token punctuation">;</span>
<span class="token keyword">fn</span> <span class="token function-definition function">main</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><p>(Where 'tutorial1_window' is the name of the project you created with Cargo earlier)</p> <p>If you only want to support desktops, that's all you have to do! In the next tutorial, we'll start using wgpu!</p> <h2 id="added-support-for-the-web"><a href="#added-support-for-the-web" class="header-anchor">#</a> Added support for the web</h2> <p>If I go through this tutorial about WebGPU and never talk about using it on the web, then I'd hardly call this tutorial complete. Fortunately, getting a wgpu application running in a browser is not too difficult once you get things set up.</p> <p>Let's start with the changes we need to make to our <code>Cargo.toml</code>:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">lib</span><span class="token punctuation">]</span>
<span class="token key property">crate-type</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;cdylib&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;rlib&quot;</span><span class="token punctuation">]</span>
</code></pre></div><p>These lines tell Cargo that we want to allow our crate to build a native Rust static library (rlib) and a C/C++ compatible library (cdylib). We need rlib if we want to run wgpu in a desktop environment. We need cdylib to create the Web Assembly that the browser will run.</p> <div class="note"><h2 id="web-assembly"><a href="#web-assembly" class="header-anchor">#</a> Web Assembly</h2> <p>Web Assembly, i.e. WASM, is a binary format supported by most modern browsers that allows lower-level languages such as Rust to run on a web page. This allows us to write the bulk of our application in Rust and use a few lines of Javascript to get it running in a web browser.</p></div> <p>Now, all we need are some more dependencies that are specific to running in WASM:</p> <div class="language-toml extra-class"><pre class="language-toml"><code><span class="token punctuation">[</span><span class="token table class-name">dependencies</span><span class="token punctuation">]</span>
<span class="token key property">cfg-if</span> <span class="token punctuation">=</span> <span class="token string">&quot;1&quot;</span>
<span class="token comment"># the other regular dependencies...</span>
<span class="token punctuation">[</span><span class="token table class-name">target.'cfg(target_arch = &quot;wasm32&quot;)'.dependencies</span><span class="token punctuation">]</span>
<span class="token key property">console_error_panic_hook</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.1.6&quot;</span>
<span class="token key property">console_log</span> <span class="token punctuation">=</span> <span class="token string">&quot;1.0&quot;</span>
<span class="token key property">wgpu</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.18&quot;</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span><span class="token string">&quot;webgl&quot;</span><span class="token punctuation">]</span><span class="token punctuation">}</span>
<span class="token key property">wasm-bindgen</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.2&quot;</span>
<span class="token key property">wasm-bindgen-futures</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.4.30&quot;</span>
<span class="token key property">web-sys</span> <span class="token punctuation">=</span> <span class="token punctuation">{</span> <span class="token key property">version</span> <span class="token punctuation">=</span> <span class="token string">&quot;0.3&quot;</span><span class="token punctuation">,</span> <span class="token key property">features</span> <span class="token punctuation">=</span> <span class="token punctuation">[</span>
<span class="token string">&quot;Document&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;Window&quot;</span><span class="token punctuation">,</span>
<span class="token string">&quot;Element&quot;</span><span class="token punctuation">,</span>
<span class="token punctuation">]</span><span class="token punctuation">}</span>
</code></pre></div><p>The <a href="https://docs.rs/cfg-if" target="_blank" rel="noopener noreferrer">cfg-if<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> crate adds a macro that makes using platform-specific code more manageable.</p> <p>The <code>[target.'cfg(target_arch = &quot;wasm32&quot;)'.dependencies]</code> line tells Cargo to only include these dependencies if we are targeting the <code>wasm32</code> architecture. The next few dependencies just make interfacing with JavaScript a lot easier.</p> <ul><li><a href="https://docs.rs/console_error_panic_hook" target="_blank" rel="noopener noreferrer">console_error_panic_hook<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> configures the <code>panic!</code> macro to send errors to the javascript console. Without this, when you encounter panics, you'll be left in the dark about what caused them.</li> <li><a href="https://docs.rs/console_log" target="_blank" rel="noopener noreferrer">console_log<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> implements the <a href="https://docs.rs/log" target="_blank" rel="noopener noreferrer">log<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> API. It sends all logs to the javascript console. It can be configured to only send logs of a particular log level. This is also great for debugging.</li> <li>We need to enable the WebGL feature on wgpu if we want to run on most current browsers. Support is in the works for using the WebGPU api directly, but that is only possible on experimental versions of browsers such as Firefox Nightly and Chrome Canary.<br>
You're welcome to test this code on these browsers (and the wgpu devs would appreciate it as well), but for the sake of simplicity, I'm going to stick to using the WebGL feature until the WebGPU api gets to a more stable state.<br>
If you want more details, check out the guide for compiling for the web on <a href="https://github.com/gfx-rs/wgpu/wiki/Running-on-the-Web-with-WebGPU-and-WebGL" target="_blank" rel="noopener noreferrer">wgpu's repo<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://docs.rs/wasm-bindgen" target="_blank" rel="noopener noreferrer">wasm-bindgen<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> is the most important dependency in this list. It's responsible for generating the boilerplate code that will tell the browser how to use our crate. It also allows us to expose methods in Rust that can be used in Javascript, and vice-versa.<br>
I won't get into the specifics of wasm-bindgen, so if you need a primer (or just a refresher), check out <a href="https://rustwasm.github.io/wasm-bindgen/" target="_blank" rel="noopener noreferrer">this<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a></li> <li><a href="https://docs.rs/web-sys" target="_blank" rel="noopener noreferrer">web-sys<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> is a crate that includes many methods and structures that are available in a normal javascript application: <code>get_element_by_id</code>, <code>append_child</code>. The features listed are only the bare minimum of what we need currently.</li></ul> <h2 id="more-code"><a href="#more-code" class="header-anchor">#</a> More code</h2> <p>First, we need to import <code>wasm-bindgen</code> in <code>lib.rs</code>:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[cfg(target_arch=<span class="token string">&quot;wasm32&quot;</span>)]</span>
<span class="token keyword">use</span> <span class="token namespace">wasm_bindgen<span class="token punctuation">::</span>prelude<span class="token punctuation">::</span></span><span class="token operator">*</span><span class="token punctuation">;</span>
</code></pre></div><p>Next, we need to tell wasm-bindgen to run our <code>run()</code> function when the WASM is loaded:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[cfg_attr(target_arch=<span class="token string">&quot;wasm32&quot;</span>, wasm_bindgen(start))]</span>
<span class="token keyword">pub</span> <span class="token keyword">fn</span> <span class="token function-definition function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// same as above for now...</span>
<span class="token punctuation">}</span>
</code></pre></div><p>Then we need to toggle what logger we are using based on whether we are in WASM land or not. Add the following to the top of the run function, replacing the <code>env_logger::init()</code> line:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token namespace">cfg_if<span class="token punctuation">::</span></span><span class="token macro property">cfg_if!</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token attribute attr-name">#[cfg(target_arch = <span class="token string">&quot;wasm32&quot;</span>)]</span> <span class="token punctuation">{</span>
<span class="token namespace">std<span class="token punctuation">::</span>panic<span class="token punctuation">::</span></span><span class="token function">set_hook</span><span class="token punctuation">(</span><span class="token class-name">Box</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token namespace">console_error_panic_hook<span class="token punctuation">::</span></span>hook<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token namespace">console_log<span class="token punctuation">::</span></span><span class="token function">init_with_level</span><span class="token punctuation">(</span><span class="token namespace">log<span class="token punctuation">::</span></span><span class="token class-name">Level</span><span class="token punctuation">::</span><span class="token class-name">Warn</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">&quot;Couldn't initialize logger&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token namespace">env_logger<span class="token punctuation">::</span></span><span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre></div><p>This will set up <code>console_log</code> and <code>console_error_panic_hook</code> in a web build and will initialize <code>env_logger</code> in a normal build. This is important as <code>env_logger</code> doesn't support Web Assembly at the moment.</p> <p>Next, after we create our event loop and window, we need to add a canvas to the HTML document that we will host our application:</p> <div class="language-rust extra-class"><pre class="language-rust"><code><span class="token attribute attr-name">#[cfg(target_arch = <span class="token string">&quot;wasm32&quot;</span>)]</span>
<span class="token punctuation">{</span>
<span class="token comment">// Winit prevents sizing with CSS, so we have to set</span>
<span class="token comment">// the size manually when on web.</span>
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>dpi<span class="token punctuation">::</span></span><span class="token class-name">PhysicalSize</span><span class="token punctuation">;</span>
window<span class="token punctuation">.</span><span class="token function">set_inner_size</span><span class="token punctuation">(</span><span class="token class-name">PhysicalSize</span><span class="token punctuation">::</span><span class="token function">new</span><span class="token punctuation">(</span><span class="token number">450</span><span class="token punctuation">,</span> <span class="token number">400</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">use</span> <span class="token namespace">winit<span class="token punctuation">::</span>platform<span class="token punctuation">::</span>web<span class="token punctuation">::</span></span><span class="token class-name">WindowExtWebSys</span><span class="token punctuation">;</span>
<span class="token namespace">web_sys<span class="token punctuation">::</span></span><span class="token function">window</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>win<span class="token closure-punctuation punctuation">|</span></span> win<span class="token punctuation">.</span><span class="token function">document</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">and_then</span><span class="token punctuation">(</span><span class="token closure-params"><span class="token closure-punctuation punctuation">|</span>doc<span class="token closure-punctuation punctuation">|</span></span> <span class="token punctuation">{</span>
<span class="token keyword">let</span> dst <span class="token operator">=</span> doc<span class="token punctuation">.</span><span class="token function">get_element_by_id</span><span class="token punctuation">(</span><span class="token string">&quot;wasm-example&quot;</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token keyword">let</span> canvas <span class="token operator">=</span> <span class="token namespace">web_sys<span class="token punctuation">::</span></span><span class="token class-name">Element</span><span class="token punctuation">::</span><span class="token function">from</span><span class="token punctuation">(</span>window<span class="token punctuation">.</span><span class="token function">canvas</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
dst<span class="token punctuation">.</span><span class="token function">append_child</span><span class="token punctuation">(</span><span class="token operator">&amp;</span>canvas<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ok</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token operator">?</span><span class="token punctuation">;</span>
<span class="token class-name">Some</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">expect</span><span class="token punctuation">(</span><span class="token string">&quot;Couldn't append canvas to document body.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre></div><div class="note"><p>The <code>&quot;wasm-example&quot;</code> id is specific to my project (aka. this tutorial). You can substitute this for whatever id you're using in your HTML. Alternatively, you could add the canvas directly to the <code>&lt;body&gt;</code> as they do in the wgpu repo. This part is ultimately up to you.</p></div> <p>That's all the web-specific code we need for now. The next thing we need to do is build the Web Assembly itself.</p> <h2 id="wasm-pack"><a href="#wasm-pack" class="header-anchor">#</a> Wasm Pack</h2> <p>Now you can build a wgpu application with just wasm-bindgen, but I ran into some issues doing that. For one, you need to install wasm-bindgen on your computer as well as include it as a dependency. The version you install as a dependency <strong>needs</strong> to exactly match the version you installed, otherwise, your build will fail.</p> <p>To get around this shortcoming, and to make the lives of everyone reading this easier, I opted to add <a href="https://rustwasm.github.io/docs/wasm-pack/" target="_blank" rel="noopener noreferrer">wasm-pack<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a> to the mix. Wasm-pack handles installing the correct version of wasm-bindgen for you, and it supports building for different types of web targets as well: browser, NodeJS, and bundlers such as webpack.</p> <p>To use wasm-pack, first, you need to <a href="https://rustwasm.github.io/wasm-pack/installer/" target="_blank" rel="noopener noreferrer">install it<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>.</p> <p>Once you've done that, we can use it to build our crate. If you only have one crate in your project, you can just use <code>wasm-pack build</code>. If you're using a workspace, you'll have to specify what crate you want to build. Imagine your crate is a directory called <code>game</code>, you would use:</p> <div class="language-bash extra-class"><pre class="language-bash"><code>wasm-pack build game
</code></pre></div><p>Once wasm-pack is done building you'll have a <code>pkg</code> directory in the same directory as your crate. This has all the javascript code needed to run the WASM code. You'd then import the WASM module in javascript:</p> <div class="language-js extra-class"><pre class="language-js"><code><span class="token keyword">const</span> init <span class="token operator">=</span> <span class="token keyword">await</span> <span class="token keyword">import</span><span class="token punctuation">(</span><span class="token string">'./pkg/game.js'</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;WASM Loaded&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre></div><p>This site uses <a href="https://vuepress.vuejs.org/" target="_blank" rel="noopener noreferrer">Vuepress<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>, so I load the WASM in a Vue component. How you handle your WASM will depend on what you want to do. If you want to check out how I'm doing things, take a look at <a href="https://github.com/sotrh/learn-wgpu/blob/master/docs/.vuepress/components/WasmExample.vue" target="_blank" rel="noopener noreferrer">this<span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></a>.</p> <div class="note"><p>If you intend to use your WASM module in a plain HTML website, you'll need to tell wasm-pack to target the web:</p> <div class="language-bash extra-class"><pre class="language-bash"><code>wasm-pack build <span class="token parameter variable">--target</span> web
</code></pre></div><p>You'll then need to run the WASM code in an ES6 Module:</p> <div class="language-html extra-class"><pre class="language-html"><code><span class="token doctype"><span class="token punctuation">&lt;!</span><span class="token doctype-tag">DOCTYPE</span> <span class="token name">html</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>html</span> <span class="token attr-name">lang</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>en<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>head</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">charset</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>UTF-8<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">http-equiv</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>X-UA-Compatible<span class="token punctuation">&quot;</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>IE=edge<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>meta</span> <span class="token attr-name">name</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>viewport<span class="token punctuation">&quot;</span></span> <span class="token attr-name">content</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>width=device-width, initial-scale=1.0<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>title</span><span class="token punctuation">&gt;</span></span>Learn WGPU<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>title</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>style</span><span class="token punctuation">&gt;</span></span><span class="token style"><span class="token language-css">
<span class="token selector">canvas</span> <span class="token punctuation">{</span>
<span class="token property">background-color</span><span class="token punctuation">:</span> black<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>style</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>head</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>body</span> <span class="token attr-name">id</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>wasm-example<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;</span>script</span> <span class="token attr-name">type</span><span class="token attr-value"><span class="token punctuation attr-equals">=</span><span class="token punctuation">&quot;</span>module<span class="token punctuation">&quot;</span></span><span class="token punctuation">&gt;</span></span><span class="token script"><span class="token language-javascript">
<span class="token keyword">import</span> init <span class="token keyword">from</span> <span class="token string">&quot;./pkg/pong.js&quot;</span><span class="token punctuation">;</span>
<span class="token function">init</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">then</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">=&gt;</span> <span class="token punctuation">{</span>
console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">&quot;WASM Loaded&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</span></span><span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>script</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>body</span><span class="token punctuation">&gt;</span></span>
<span class="token tag"><span class="token tag"><span class="token punctuation">&lt;/</span>html</span><span class="token punctuation">&gt;</span></span>
</code></pre></div></div> <p>Press the button below, and you will see the code running!</p> <div id="wasm-example"><!----> <button>Try Tutorial1_window!</button></div> <div class="auto-github-link"><a href="https://github.com/sotrh/learn-wgpu/tree/master/code/beginner/tutorial1-window/" target="_blank" rel="noopener noreferrer">Check out the code!</a> <span><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewBox="0 0 100 100" width="15" height="15" class="icon outbound"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path> <polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg> <span class="sr-only">(opens new window)</span></span></div></div> <footer class="page-edit"><!----> <div class="last-updated"><span class="prefix">Last Updated: </span> <span class="time">11/28/2023, 12:41:06 AM</span></div></footer> <div class="page-nav"><p class="inner"><span class="prev">
<a href="/learn-wgpu/" class="prev router-link-active">
Introduction
</a></span> <span class="next"><a href="/learn-wgpu/beginner/tutorial2-surface/">
The Surface
</a>
</span></p></div> </main></div></div><div class="global-ui"><!----></div></div>
<script src="/learn-wgpu/assets/js/app.9afc5d83.js" defer></script><script src="/learn-wgpu/assets/js/2.2ef7287a.js" defer></script><script src="/learn-wgpu/assets/js/1.eaeeb819.js" defer></script><script src="/learn-wgpu/assets/js/55.79d255a9.js" defer></script><script src="/learn-wgpu/assets/js/33.c548d7f9.js" defer></script><script src="/learn-wgpu/assets/js/37.5ecf7ce2.js" defer></script>
</body>
</html>