├── 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 |
--------------------------------------------------------------------------------