├── readme.md ├── copying ├── index.html └── canvas.wast /readme.md: -------------------------------------------------------------------------------- 1 | # WebAssembly Canvas2D example 2 | 3 | A simple animation on Canvas2D with WebAssembly. [See it live](https://subzey.github.io/wasm-canvas2d/) 4 | 5 | Though it's not very valuable in terms of aesthetics, that example could help someone to dive into WebAssembly. It features: 6 | 7 | - Calls of JS functions from WebAssembly 8 | - Calls of WebAsm functions from JS 9 | - Using stack 10 | - Using simple loops 11 | 12 | Please see `canvas.wast` for the annotated source. -------------------------------------------------------------------------------- /copying: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 63 | 64 | -------------------------------------------------------------------------------- /canvas.wast: -------------------------------------------------------------------------------- 1 | (module 2 | ;; import ctx.beginPath as a function with no arguments and void result 3 | (func $beginPath (import "ctx" "beginPath")) 4 | 5 | ;; import ctx.stroke as a function with no arguments and void result 6 | (func $stroke (import "ctx" "stroke")) 7 | 8 | ;; import ctx.lineTo as a function with 2 float64 arguments and void result 9 | (func $lineTo (import "ctx" "lineTo") (param $x f64) (param $y f64)) 10 | 11 | ;; import ctx.lineTo as a function with 4 float64 arguments and void result 12 | (func $clearRect (import "ctx" "clearRect") (param $x f64) (param $y f64) (param $w f64) (param $h f64)) 13 | 14 | ;; import Math.sin as a function float64 => float64 15 | (func $sin (import "Math" "sin") (param $angle f64) (result f64)) 16 | 17 | ;; declare anonymous function and export right away as "draw" 18 | (func (export "draw") (param $timestamp f64) 19 | ;; let phase: float64 = 0 20 | (local $phase f64) 21 | ;; let count: int32 = 0 22 | (local $count i32) 23 | 24 | ;; clean up canvas 25 | (call $clearRect 26 | (f64.const 0) (f64.const 0) (f64.const 300) (f64.const 150) 27 | ) 28 | 29 | ;; NOTE: It looks like arguments, but actually, it's just an another way to push 30 | ;; values on top of the stack. 31 | ;; `(call $clearRect (f64.const 0) (f64.const 0) (f64.const 300) (f64.const 150) )` 32 | ;; is just the same as 33 | ;; `(f64.const 0) (f64.const 0) (f64.const 300) (f64.const 150) (call $clearRect)` 34 | ;; But it's clearly more readable ...until the nesting become too deep. 35 | 36 | 37 | 38 | ;; ctx.beginPath() 39 | (call $beginPath) 40 | 41 | ;; count = 3000 42 | (set_local $count (i32.const 3000)) 43 | 44 | ;; Mark loop start 45 | (loop $continue 46 | ;; May the Forth be with you. 47 | ;; (https://en.wikipedia.org/wiki/Forth_(programming_language)#Programmer.27s_perspective) 48 | 49 | (f64.convert_u/i32 (get_local $count)) ;; Treat int32 as unsigned int32 and convert to float 50 | (f64.add (get_local $timestamp)) ;; Add up with $timestamp 51 | (f64.div (f64.const 1000)) ;; Divide by 1000 (animation speed) 52 | (tee_local $phase) ;; Save phase to $phase and leave on top of the stack 53 | (call $sin) ;; Ask JS Math function to calc sine 54 | (f64.mul (f64.const 149)) ;; This would be an X coord. Scale by 149 55 | (f64.add (f64.const 150)) ;; Translate by 150 56 | 57 | ;; Stack size here is 1: [f64] 58 | 59 | (get_local $phase) ;; Restore $phase 60 | (f64.mul (f64.const 1.75)) ;; Multiply by 3/4 to get a nice Lissajous curve 61 | (f64.const 1.5707963267948966) ;; Pi/2. Wasm is a binary format, so there's no penalty for being too precise 62 | (f64.add) 63 | (call $sin) ;; Math.sin(). But since we've added Pi/2, it's actually a cos. Or -cos. Who cares if it looks good? 64 | (f64.mul (f64.const 74)) ;; This would be an Y coord. Scale by 74 65 | (f64.add (f64.const 75)) ;; Translate by 75 66 | 67 | ;; Stack size here is 2: [f64] [f64] 68 | 69 | ;; Call lineTo with two topmost stack values 70 | (call $lineTo) 71 | 72 | ;; Subtract 30 from $count and place result on top of stack 73 | (i32.sub (get_local $count) (i32.const 30)) 74 | ;; Save new value to $count *and leave that value on top of stack* 75 | (tee_local $count) 76 | 77 | ;; Branch ("goto") to the start of the loop if the topmost i32 value is not zero 78 | (br_if $continue) 79 | ) 80 | 81 | ;; Finally, stroke() 82 | (call $stroke) 83 | ) 84 | ) 85 | --------------------------------------------------------------------------------