forked from hakimel/reveal.js
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
560 lines (545 loc) · 22.1 KB
/
Copy pathindex.html
File metadata and controls
560 lines (545 loc) · 22.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Discover WebAssembly</title>
<link rel="stylesheet" href="dist/reset.css">
<link rel="stylesheet" href="dist/reveal.css">
<link rel="stylesheet" href="dist/theme/black.css">
<link rel="icon" type="image/png" href="assets/wasm-logo.png" />
<!-- Theme used for syntax highlighted code -->
<link rel="stylesheet" href="plugin/highlight/monokai.css">
</head>
<body>
<div class="reveal">
<div class="slides">
<section>
<p>Qu'est-ce que le</p>
<h1>WebAssembly</h1>
</section>
<!-- *************** PRINCIPE ***************** -->
<section>
<h3>1. Principe</h3>
<section>
<p>Le WebAssembly (wasm) est un bytecode executé dans une machine virtuelle, interpretable par des
navigateurs web. Il permet d'exécuter un code performant, sécurisé et très bas niveau par
rapport
aux languages web habituels.</p>
</section>
<section data-auto-animate>
<h4>1.1 Performances</h4>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<ul>
<li> Le WebAssembly est un langage machine qui peut être executé directement depuis le
navigateur
</li>
<li> Bien que le JavaScript soit désormais également compilé par les navigateurs pour de
meilleurs performances, le WebAssembly possède un avantage indéniable : <a
href="https://react-etc.net/entry/webassembly-vs-javascript-streaming-compilation-performance-advantage"
target="_blank">la
Streaming
compilation</a>
</li>
</ul>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<h4>JavaScript</h4>
<img src="./assets/javascript.png" alt="logo">
<p>En JavaScript, chaque fichier contenant le code doit être <span>totalement téléchargé</span> par
le
client avant que celui-ci puisse commencer à le compiler en code natif.</p>
</section>
<section data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<h4>JavaScript</h4>
<img src="./assets/javascript.png" alt="logo">
<p>En JavaScript, chaque fichier contenant le code doit être <span style="color: red;">totalement
téléchargé</span> par le
client avant que celui-ci puisse commencer à le compiler en code natif.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<h4>WASM</h4>
<img src="./assets/wasm.png" alt="logo">
<p>En WebAssembly, le code est <span>streamé vers l'utilisateur</span> et la compilation en code
natif
démarre dès les premiers bits reçus.</p>
</section>
<section data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<h4>WASM</h4>
<img src="./assets/wasm.png" alt="logo">
<p>En WebAssembly, le code est <span style="color: red;">streamé vers l'utilisateur</span> et la
compilation en code natif
démarre dès les premiers bits reçus.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<p>Cette différence de fonctionnement entre les deux langages donne un avantage certain
au wasm en terme de temps de démarrage, notamment lorsque la connexion est moins
bonne (sur les appareils mobiles par exemple).</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<p>Le WebAssembly compilé donne également de meilleurs résultats que le JavaScript
compilé, notamment sur mobile : <a
href="https://medium.com/@torch2424/webassembly-is-fast-a-real-world-benchmark-of-webassembly-vs-es6-d85a23f8e193?p=783c454449cd"
target="_blank">Voir
ce
benchmark</a>
</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.1 Performances</h4>
<p>Le WebAssembly compilé donne également de meilleurs résultats que le JavaScript
compilé, notamment sur mobile : <a
href="https://medium.com/@torch2424/webassembly-is-fast-a-real-world-benchmark-of-webassembly-vs-es6-d85a23f8e193?p=783c454449cd"
target="_blank">Voir
ce
benchmark</a>
</p>
<p> Le gain en vitesse de chargement est de l'ordre de 30% <ins>minimum</ins>.
</p>
</section>
<section data-auto-animate>
<h4>1.2 Sécurité</h4>
</section>
<section data-transition="fade" data-auto-animate>
<h4 class="subtitle">1.2 Sécurité</h4>
<p data-id="main_text">Le WebAssembly est executé dans un environnement dit <a
href="https://webassembly.org/docs/security/" target="_blank">sandbox</a>
, tout comme le JavaScript, il possède donc les mêmes caractéristiques en terme de sécurité.
<p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.2 Sécurité</h4>
<p data-id="main_text">Le WebAssembly est executé dans un environnement dit <a
href="https://webassembly.org/docs/security/" target="_blank">sandbox</a>
, tout comme le JavaScript, il possède donc les mêmes caractéristiques en terme de sécurité.
<p>
<p>On ne peut utiliser que des APIs fournies par la machine virtuelle (à l'inverse d'un langage
comme Java qui peut faire des appels système via Java.io via la jvm par exemple)</p>
</section>
<section data-transition="fade">
<h4 class="subtitle">1.2 Sécurité</h4>
<p>Enfin, les failles de type <a
href="https://owasp.org/www-community/attacks/Buffer_overflow_attack" target="_blank">stack
overflow</a> sont rendues inexploitable de par la
conception même du WebAssembly : <span class="red">il n'existe pas de principe de mémoire
exécutable.</span>
</p>
</section>
<section data-auto-animate data-transition="fade">
<h4>1.3 Bas-niveau</h4>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.3 Bas-niveau</h4>
<p>Le WebAssembly étant compilé dans un bytecode proche du langage machine, cela permet de réaliser
des <span class="red">optimisations très fines en terme d'allocation mémoire.</span></p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">1.3 Bas-niveau</h4>
<p>Cependant, ce bytecode est à destination d'une <span class="red"> machine virtuelle</span>, ce
qui permet de s'affranchir de l'architecture du processeur utilisé par le client pour exécuter
le code. </p>
</section>
</section>
<!-- *************** EXEMPLE ***************** -->
<section>
<h2>2. Exemple</h2>
<section data-auto-animate data-transition="fade">
<p>
Le WebAssembly étant un langage machine, il faut écrire son programme dans un langage de base
puis le compiler en wasm.
Pour cet exemple, nous nous appuyerons sur un code en C/C++ (basé sur <a target="_blank"
href="https://blog.esciencecenter.nl/using-c-in-a-web-app-with-webassembly-efd78c08469">cet
article</a>).
</p>
</section>
<section data-auto-animate data-transition="fade">
<h4>2.1 Le code C++</h4>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.1 Le code C++</h4>
<p>Le but de ce programme simple est de calculer la racine d'une fonction selon la <a
target="_blank" href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Newton">méthode de
newton.</a> (ou Newton-Raphson)</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.1 Le code C++</h4>
<p>Le but de ce programme simple est de calculer la racine d'une fonction selon la <a
target="_blank" href="https://fr.wikipedia.org/wiki/M%C3%A9thode_de_Newton">méthode de
newton.</a> (ou Newton-Raphson)</p>
<p>Nous avons besoin pour cela de prendre en paramètre une fonction ainsi que sa dérivée.</p>
</section>
<section data-transition="fade">
<h4 class="subtitle">2.1 Le code C++</h4>
<pre><code data-line-numbers>// Exemple d'equation
float equation(float x) {
return 2 * x * x * x - 4 * x * x + 6;
}
// Dérivée de l'équation ci-dessus
float derivative(float x) {
return 6 * x * x - 8 * x;
}
</code></pre>
<p class="legende">problem.cpp</p>
<p class="small-text">Voici le code de l'équation dont la racine est recherchée, ainsi que sa
dérivée
(les header files sont exclus).
</p>
</section>
<section data-transition="fade" data-auto-animate>
<h4 class="subtitle">2.1 Le code C++</h4>
<pre>
<code data-line-numbers="2">
NewtonRaphson::NewtonRaphson(float tolerance_in) : tolerance(tolerance_in) {}
float NewtonRaphson::solve(float initial_guess) {
float x = initial_guess;
float delta_x = 0;
do {
delta_x = equation(x) / derivative(x);
x = x - delta_x;
} while (std::abs(delta_x) >= tolerance);
return x;
};
</code>
</pre>
<p class="legende">newtonraphson.cpp</p>
<p class="small-text">La classe est initialisée avec une valeur de tolérance.</p>
</section>
<section data-transition="fade" data-auto-animate>
<h4 class="subtitle">2.1 Le code C++</h4>
<pre>
<code data-line-numbers="4-12">
NewtonRaphson::NewtonRaphson(float tolerance_in) : tolerance(tolerance_in) {}
float NewtonRaphson::solve(float initial_guess) {
float x = initial_guess;
float delta_x = 0;
do {
delta_x = equation(x) / derivative(x);
x = x - delta_x;
} while (std::abs(delta_x) >= tolerance);
return x;
};
</code>
</pre>
<p class="legende">newtonraphson.cpp</p>
<p class="small-text">Ensuite, la méthode solve de la classe peut être appelée pour trouver
récursivement la racine de l'équation.</p>
</section>
<section data-transition="fade" data-auto-animate>
<h4 class="subtitle">2.1 Le code C++</h4>
<pre>
<code data-line-numbers>int main(){
float initial_guess = -4;
float tolerance = 0.001;
NewtonRaphson newtonraphson(tolerance);
float root = newtonraphson.solve(initial_guess);
std::cout << root << std::endl;
}
</code>
</pre>
<p class="small-text">Un code comme celui-ci nous permet d'obtenir root = -1, ce
qui correspond bien à la valeur de la racine de l'équation définie plus tôt.
</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.1 Le code C++</h4>
<pre>
<code data-line-numbers data-trim>
<script type="text/template">
using namespace emscripten;
EMSCRIPTEN_BINDINGS(newtonraphson) {
class_<NewtonRaphson>("NewtonRaphson")
.constructor<float>()
.function("solve", &NewtonRaphson::solve)
;
}
</script>
</code>
</pre>
<p class="legende">bindings.cpp</p>
<p class="small-text">Enfin, il convient de définir un fichier dit de "binding" qui permetra
d'effectuer des appels au
code c++ depuis le javascript.
Ce code est écrit en utilisant <a target="_blank"
href="https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html#classes">les
méthodes de binding de emscripten</a>, qui est l'outil qui servira plus tard à compiler le
code
en wasm.
</p>
</section>
<section data-transition="fade" data-auto-animate>
<h4>2.2 Compiler en wasm</h4>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<p>Il s'agit de l'étape la plus importante et la plus délicate à réaliser : </p>
<ul>
<li class="fragment fade-in">Pour du C/C++ l'outil utilisé est <a target="_blank"
href="https://emscripten.org/">emscripten</a></li>
<li class="fragment fade-in">Il faut compiler le code en module wasm utilisable directement
depuis un code en JavaScript</li>
</ul>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<p>La façon la plus simple et stable d'utiliser emscripten est de passer par <a target="_blank"
href="https://hub.docker.com/r/emscripten/emsdk">l'image docker officielle</a> qui
permet de s'affranchir de la configuration du système hôte et d'éviter l'étape d'installation.
</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<p>Voici la commande qui permettra de générer le module JavaScript capable d'excuter cotre code :
</p>
<pre>
<code data-line-numbers>docker run \
--rm \
-v $(pwd):/src \
-u $(id -u):$(id -g) \
emscripten/emsdk \
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="1-2">docker run \
--rm \
-v $(pwd):/src \
-u $(id -u):$(id -g) \
emscripten/emsdk \
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p class="small-text">Dans un premier temps, on lance un conteneur qui sera automatiquement détruit
après
utilisation.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="3">docker run \
--rm \
-v $(pwd):/src \
-u $(id -u):$(id -g) \
emscripten/emsdk \
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p class="small-text">On spécifie ensuite un volume de travail correspondant au dossier courant.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="4">docker run \
--rm \
-v $(pwd):/src \
-u $(id -u):$(id -g) \
emscripten/emsdk \
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p class="small-text">La commande est exécutée avec l'utilisateur courant, ainsi les fichiers
générés auront les droits d'exécution corrects.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="5">docker run \
--rm \
-v $(pwd):/src \
-u $(id -u):$(id -g) \
emscripten/emsdk \
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p class="small-text">Le nom de l'image officielle d'emscripten.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="6-8">docker run \
--rm \
-v $(pwd):/src \
-u $(id -u):$(id -g) \
emscripten/emsdk \
emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p class="small-text">C'est cette commande qui permet de compiler notre code.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="1">emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p class="small-text">-Oz permet de spécifier au compilateur d'effectuer une optimisation sur la
taille du fichier produit (il existe <a target="_blank"
href="https://emscripten.org/docs/compiling/Building-Projects.html#building-projects-with-optimizations">plusieurs
type d'optimisations</a>).<br>
L'option <a target="_blank"
href="https://emscripten.org/docs/getting_started/FAQ.html#how-can-i-tell-when-the-page-is-fully-loaded-and-it-is-safe-to-call-compiled-functions">MODULARIZE</a>
permet d'encapsuler le code JavaScript dans une fonction de type factory, qui s'assure que le
code est bien chargé avant d'essayer de l'instancier.</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="2">emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p>Un nom d'export pour le module est défini</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers="3">emcc -I. -o newtonraphson.js -Oz -s MODULARIZE=1 \
-s EXPORT_NAME=createModule --bind \
problem.cpp newtonraphson.cpp bindings.cpp
</code>
</pre>
<p>Enfin, les fichiers c++ sont spécifiés (ils doivent se trouver dans le répertoire courant).</p>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<p>Deux fichiers sont générés par emscripten :</p>
<ul>
<li class="fragment fade-in">Un fichier wasm qui contient les instruction de notre code c++</li>
<li class="fragment fade-in">Un fichier js qui contient un code "glue" permettant d'instancier
facilement le module wasm</li>
</ul>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<p>On peut très simplement importer notre module JavaScript dans une page web classique :</p>
<pre>
<code>
<script type="text/template">
<head>
<script type="text/javascript" src="newtonraphson.js"/>
</head>
</script>
</code>
</pre>
</section>
<section data-auto-animate data-transition="fade">
<h4 class="subtitle">2.2 Compiler en wasm</h4>
<pre>
<code data-line-numbers>createModule().then(({NewtonRaphson}) => {
// Valeur d'entrée
const initial_guess = -4;
const tolerance = 0.001;
// On effectue le calcul
const newtonraphson = new NewtonRaphson(tolerance);
const root = newtonraphson.solve(initial_guess);
});
</code>
</pre>
<p>Et enfin instancier notre classe dans un script. La valeur de root correspond bien à la valeur
calculée par notre script.</p>
</section>
<section>
<p>La liste complète des fichiers nécessaires à la réalisation de ce test ainsi que des instructions
sont disponibles <a target="_blank"
href="https://github.com/ibethus/wasm-newtonraphson.git">ici</a>.</p>
</section>
</section>
</section>
<section>
<!-- *************** DEMOS ***************** -->
<section>
<h2>3. Démo</h2>
</section>
<section>
<p>
Certains projets sont relativement avancés en WebAssembly, notamment <a target="_blank"
href="https://github.com/kripken/ammo.js">Ammo</a>, qui est un portage du moteur physique
Bullet écrit en C++.
Cette librairie permet de réaliser des projet en 3D avec une physique réaliste et optimisés pour
le web.
Sur la diapo suivante, un exemple de ce dont est capable Ammo.
</p>
</section>
<section style="width: 100%; height: 100%;">
<iframe id="3DSimCar" allowfullscreen="true" mozallowfullscreen="true" webkitallowfullscreen="true"
allow="autoplay"
data-src="https://rawcdn.githack.com/kripken/ammo.js/99d0ec0b1e26d7ccc13e013caba8e8a5c98d953b/examples/webgl_demo_vehicle/index.html"
style="width: 100%; height: 100%; max-height: 90%; max-width: 100%;"
src="https://rawcdn.githack.com/kripken/ammo.js/99d0ec0b1e26d7ccc13e013caba8e8a5c98d953b/examples/webgl_demo_vehicle/index.html"></iframe>
<button onclick="getControl()">Prendre le contrôle</button>
</section>
<section>
<p>Il existe également des outils en ligne permettant de réaliser des tests sur de petits programmes,
compilant à la volée le code C/C++ en wasm, notamment <a target="_blank"
href="https://mbebenita.github.io/WasmExplorer/">WasmExplorer</a></p>
</section>
</section>
<!-- *************** SOURCES ***************** -->
<section>
<h2>4. Sources</h2>
<section data-transition="fade">
<p>Le site du Netherlands eScience Center, dont est extrait notre exemple,
propose des axes d'amélioration pour notre petit programme en wasm sous forme de tutoriel,
indispensable pour en apprendre plus (à la fin de l'article).
</p>
<a target="_blank" href="https://blog.esciencecenter.nl/using-c-in-a-web-app-with-webassembly-efd78c08469">Voir le lien</a>
</section>
<section data-transition="fade">
<p>JavaScript January fournit l'article le plus complet et compréhensible sur
le WebAssembly et son fonctionnement.
</p>
<a target="_blank" href="https://www.javascriptjanuary.com/blog/webassembly-neither-web-nor-assembly-but-revolutionary">Voir le lien.</a>
</section>
<section>
<p>Ce dépôt GitHub recense de nombreux projets passionnants, écrits en WebAssembly.</p>
<a target="_blank" href="https://github.com/mbasso/awesome-wasm">Voir le lien.</a>
</section>
</section>
</section>
</div>
</div>
<script src="dist/reveal.js"></script>
<script src="plugin/notes/notes.js"></script>
<script src="plugin/markdown/markdown.js"></script>
<script src="plugin/highlight/highlight.js"></script>
<script>
// More info about initialization & config:
// - https://revealjs.com/initialization/
// - https://revealjs.com/config/
Reveal.initialize({
hash: true,
// Learn about plugins: https://revealjs.com/plugins/
plugins: [RevealMarkdown, RevealHighlight, RevealNotes]
});
function getControl() {
var iframe = document.getElementById("3DSimCar");
iframe.contentWindow.focus();
}
</script>
</body>
</html>