diff --git a/favicon.php b/favicon.php
new file mode 100644
index 0000000..16c34ce
--- /dev/null
+++ b/favicon.php
@@ -0,0 +1,44 @@
+<?php
+header('Content-Type: image/x-icon');
+
+const SIZE = 16;
+const WALL = 1;
+const GROUND = 0;
+
+$favicon     = imagecreatetruecolor(SIZE, SIZE);
+$wallColor   = imagecolorallocate($favicon, 165, 80, 30);
+$groundColor = imagecolorallocate($favicon, 203, 162, 133);
+
+imagefill($favicon, 0, 0, $wallColor);
+
+$maze = array();
+for ($y = 0; $y < SIZE; $y++) {
+    $maze[$y] = array();
+    for ($x = 0; $x < SIZE; $x++) {
+        $maze[$y][$x] = WALL;
+    }
+}
+
+function dig($position) {
+    global $maze;
+    global $favicon;
+    global $groundColor;
+    $directions = [[0, 1], [0, -1], [1, 0], [-1, 0]];
+    shuffle($directions);
+    foreach ($directions as $direction) {
+        $step1 = [$position[0] + $direction[0], $position[1] + $direction[1]];
+        $step2 = [$step1[0] + $direction[0], $step1[1] + $direction[1]];
+        if (0 <= $step2[1] and $step2[1] < SIZE and 0 <= $step2[0] and $step2[0] < SIZE and $maze[$step2[1]][$step2[0]] == WALL) {
+            $maze[$step1[1]][$step1[0]] = GROUND;
+            imagesetpixel($favicon, $step1[0], $step1[1], $groundColor);
+            $maze[$step2[1]][$step2[0]] = GROUND;
+            imagesetpixel($favicon, $step2[0], $step2[1], $groundColor);
+            dig($step2);
+        }
+    }
+}
+
+dig([1, 1]);
+imagebmp($favicon);
+imagedestroy($favicon);
+?>
\ No newline at end of file
diff --git a/index.html b/index.html
old mode 100644
new mode 100755
index c2023d0..812d997
--- a/index.html
+++ b/index.html
@@ -1,29 +1,31 @@
 <!DOCTYPE html>
-<html>
-	<head>
-		<meta charset="utf-8" />
-		<title>Labyrinthe</title>
+<html lang='fr' dir="ltr" prefix="og: https://ogp.me/ns#">
+    <head>
+        <meta charset="utf-8"/>
+        <title>Labyrinthe</title>
         <script type="text/javascript" src="labyrinthe.js"></script>
-		<link rel="shortcut icon" type="image/png" href="mur.png"/>
-		<link rel="stylesheet" type="text/css" href="style.css" />
-		<link rel=”image_src” href="thumbnail.png" />
-		<meta property="og:title" content="Labyrinthe" />
-		<meta property="og:type" content="game" />
-		<meta property="og:url" content="https://malingrey.fr/laby" />
-		<meta property="og:image" content="https://malingrey.fr/laby/thumbnail.png" />
-		<meta property="og:image:width" content="250" />
-		<meta property="og:image:height" content="250" />
-		<meta property="og:description" content="Trouveras-tu le fromage ?" />
-		<meta property="og:locale" content="fr_FR" />
+        <link rel="shortcut icon" type="image/png" href="favicon.php"/>
+        <link rel="stylesheet" type="text/css" href="style.css"/>
+        <link rel=”image_src” href="thumbnail.png"/>
+        <link rel="manifest" href="manifest.json">
+        <meta property="og:title" content="Labyrinthe"/>
+        <meta property="og:type" content="website"/>
+        <meta property="og:url" content="https://adrien.malingrey.fr/jeux/laby/"/>
+        <meta property="og:image" content="https://adrien.malingrey.fr/jeux/laby/thumbnail.png"/>
+        <meta property="og:image:width" content="250"/>
+        <meta property="og:image:height" content="250"/>
+        <meta property="og:description" content="Trouveras-tu le fromage ?"/>
+        <meta property="og:locale" content="fr_FR"/>
+        <meta property="og:site_name" content="adrien.malingrey.fr"/>
     </head>
-	<body>
-	    <div style="display:none;">
+    <body>
+        <div style="display:none;">
             <img id="mur" src="mur.png">
             <img id="sol" src="sol.png">
             <img id="pas" src="pas.png">
             <img id="fromage" src="fromage.png">
             <img id="souris" src="souris.png">
         </div>
-		<canvas id="canvas" width="795" height="585">Votre navigateur ne supporte pas HTML5, veuillez le mettre à jour pour jouer.</canvas>
-	</body>
+        <canvas id="canvas" width="795" height="585">Votre navigateur ne supporte pas HTML5, veuillez le mettre à jour pour jouer.</canvas>
+    </body>
 </html>
diff --git a/labyrinthe.js b/labyrinthe.js
old mode 100644
new mode 100755
index 1840de4..eab90c4
--- a/labyrinthe.js
+++ b/labyrinthe.js
@@ -1,209 +1,229 @@
 // Customize Array to be use as coordinates
-Object.defineProperty(Array.prototype, "x", {
-    get: function () { return this[0] },
-    set: function (x) { this[0] = x}
+Object.defineProperties(Array.prototype, {
+    "x": {
+        get: function() { return this[0] },
+        set: function(x) { this[0] = x }
+    },
+    "y": {
+        get: function() { return this[1] },
+        set: function(y) { this[1] = y }
+    }
 })
-Object.defineProperty(Array.prototype, "y", {
-    get: function () { return this[1] },
-    set: function (y) { this[1] = y}
-})
-Array.prototype.plus = function(other)  { return this.map((x, i) => x + other[i]) }
+Array.prototype.plus = function (other) {
+    return this.map((x, i) => x + other[i]);
+};
 
 const DIRECTION = {
-    "BAS": 0,
-    "GAUCHE": 1,
-    "DROITE": 2,
-    "HAUT": 3
-}
+    'BAS': 0,
+    'GAUCHE': 1,
+    'DROITE': 2,
+    'HAUT': 3,
+};
 
 const MOUVEMENT = {
-    "ARRET": [0, 0],
-    "BAS": [0, 1],
-    "HAUT": [0, -1],
-    "GAUCHE": [-1, 0],
-    "DROITE": [1, 0]
-}
+    'ARRET': [0, 0],
+    'BAS': [0, 1],
+    'HAUT': [0, -1],
+    'GAUCHE': [-1, 0],
+    'DROITE': [1, 0],
+};
 
 const ACTIONS = {
-    "ArrowUp": {"direction": DIRECTION.HAUT, "mouvement": MOUVEMENT.HAUT},
-    "ArrowDown": {"direction": DIRECTION.BAS, "mouvement": MOUVEMENT.BAS},
-    "ArrowLeft": {"direction": DIRECTION.GAUCHE, "mouvement": MOUVEMENT.GAUCHE},
-    "ArrowRight": {"direction": DIRECTION.DROITE, "mouvement": MOUVEMENT.DROITE},
-}
+    'ArrowUp': { 'direction': DIRECTION.HAUT, 'mouvement': MOUVEMENT.HAUT },
+    'z': { 'direction': DIRECTION.HAUT, 'mouvement': MOUVEMENT.HAUT },
+    'ArrowDown': { 'direction': DIRECTION.BAS, 'mouvement': MOUVEMENT.BAS },
+    's': { 'direction': DIRECTION.BAS, 'mouvement': MOUVEMENT.BAS },
+    'ArrowLeft': { 'direction': DIRECTION.GAUCHE, 'mouvement': MOUVEMENT.GAUCHE },
+    'q': { 'direction': DIRECTION.GAUCHE, 'mouvement': MOUVEMENT.GAUCHE },
+    'ArrowRight': { 'direction': DIRECTION.DROITE, 'mouvement': MOUVEMENT.DROITE },
+    'd': { 'direction': DIRECTION.DROITE, 'mouvement': MOUVEMENT.DROITE },
+};
 
 const TYPE = {
-    "MUR": 1,
-    "SOL": 2,
-    "PAS": 3
-}
+    'MUR': 1,
+    'SOL': 2,
+    'PAS': 3,
+};
+
+const DIRECTIONS_LABYRINTHE = [MOUVEMENT.BAS, MOUVEMENT.HAUT, MOUVEMENT.GAUCHE, MOUVEMENT.DROITE];
+const TAILLE_TUILE = 15;
 
-const DIRECTIONS_LABYRINTHE = [MOUVEMENT.BAS, MOUVEMENT.HAUT, MOUVEMENT.GAUCHE, MOUVEMENT.DROITE]
-const TAILLE_TUILE = 15
-	
 function dessinerTuile(context, image, x, y) {
-    context.drawImage(image, TAILLE_TUILE*x, TAILLE_TUILE*y);
+    context.drawImage(image, TAILLE_TUILE * x, TAILLE_TUILE * y);
 }
 
 class Labyrinthe extends Array {
     constructor(largeur, hauteur, context, tuiles) {
-        super()
-        this.hauteur = hauteur
-        this.largeur = largeur
-        this.context = context
-        this.tuiles = tuiles
-        for (var ligne=0; ligne < hauteur; ligne++) {
-            this.push(Array(largeur).fill(TYPE.MUR))
+        super();
+        this.hauteur = hauteur;
+        this.largeur = largeur;
+        this.context = context;
+        this.tuiles = tuiles;
+        for (var ligne = 0; ligne < hauteur; ligne++) {
+            this.push(Array(largeur).fill(TYPE.MUR));
         }
-        this.positionInitiale = [1, 1]
-        this.positionFinale = [largeur - 2, hauteur - 2]
-        this.creuse(this.positionFinale)
-        this.construit(this.positionFinale)
+        this.positionInitiale = [1, 1];
+        this.positionFinale = [largeur - 2, hauteur - 2];
+        this.creuse(this.positionFinale);
+        this.construit(this.positionFinale);
     }
 
     construit(position) {
-        for (var direction of Array.from(DIRECTIONS_LABYRINTHE).sort(x => .5 - Math.random())) {
-            var pas1 = position.plus(direction)
-            var pas2 = pas1.plus(direction)
+        for (var direction of Array.from(DIRECTIONS_LABYRINTHE).sort(x => 0.5 - Math.random())) {
+            var pas1 = position.plus(direction);
+            var pas2 = pas1.plus(direction);
             if (this.type(pas2) == TYPE.MUR) {
-                this.creuse(pas1)
-                this.creuse(pas2)
-                this.construit(pas2)
+                this.creuse(pas1);
+                this.creuse(pas2);
+                this.construit(pas2);
             }
         }
     }
-    
+
     creuse(position) {
-        this[position.y][position.x] = TYPE.SOL
+        this[position.y][position.x] = TYPE.SOL;
     }
 
     type(position) {
-        if (0 <= position.x && position.x < this.largeur && 0 <= position.y && position.y < this.hauteur) {
-            return this[position.y][position.x]
+        if (
+            0 <= position.x &&
+            position.x < this.largeur &&
+            0 <= position.y &&
+            position.y < this.hauteur
+        ) {
+            return this[position.y][position.x];
         } else {
-            return -1
+            return -1;
         }
     }
 
     dessiner() {
         this.forEach((ligne, y) => {
             ligne.forEach((type, x) => {
-                dessinerTuile(this.context, this.tuiles[type], x, y)
-            })
-        })
+                dessinerTuile(this.context, this.tuiles[type], x, y);
+            });
+        });
     }
 }
 
 class Souris {
     constructor(position, context, sprites) {
-        this.position = position
-        this.context = context
-        this.sprites = sprites
-        this.futurePosition = this.position
-        this.direction = DIRECTION.DROITE
-        this.mouvement = MOUVEMENT.ARRET
-        this.tailleSprite = 48
-        this.animationSprite = 0
-        this.animation = 0
+        this.position = position;
+        this.context = context;
+        this.sprites = sprites;
+        this.futurePosition = this.position;
+        this.direction = DIRECTION.DROITE;
+        this.mouvement = MOUVEMENT.ARRET;
+        this.tailleSprite = 48;
+        this.animationSprite = 0;
+        this.animation = 0;
     }
-    
+
     bouger(touche, labyrinthe) {
         if (touche in ACTIONS) {
-            this.direction = ACTIONS[touche].direction
-            this.mouvement = ACTIONS[touche].mouvement
-            var futurePosition = this.position.plus(this.mouvement)
+            this.direction = ACTIONS[touche].direction;
+            this.mouvement = ACTIONS[touche].mouvement;
+            var futurePosition = this.position.plus(this.mouvement);
             if ([TYPE.SOL, TYPE.PAS].includes(labyrinthe.type(futurePosition))) {
-                labyrinthe[this.position.y][this.position.x] = TYPE.PAS
-                this.futurePosition = futurePosition
-                return true
+                labyrinthe[this.position.y][this.position.x] = TYPE.PAS;
+                this.futurePosition = futurePosition;
+                return true;
             } else {
-                this.mouvement = MOUVEMENT.ARRET
-                this.animation = 0
-                return false
+                this.mouvement = MOUVEMENT.ARRET;
+                this.animation = 0;
+                return false;
             }
         } else {
-            return False
+            return False;
         }
     }
-    
+
     dessiner() {
-	    this.context.drawImage(
-	        this.sprites,
-	        this.tailleSprite * this.animationSprite,
-	        this.tailleSprite * this.direction,
-	        this.tailleSprite,
-	        this.tailleSprite,
-	        TAILLE_TUILE * this.position.x - 17 + this.mouvement.x * this.animation,
-	        TAILLE_TUILE * this.position.y - 12 + this.mouvement.y * this.animation,
-	        this.tailleSprite,
-	        this.tailleSprite
+        this.context.drawImage(
+            this.sprites,
+            this.tailleSprite * this.animationSprite,
+            this.tailleSprite * this.direction,
+            this.tailleSprite,
+            this.tailleSprite,
+            TAILLE_TUILE * this.position.x - 17 + this.mouvement.x * this.animation,
+            TAILLE_TUILE * this.position.y - 12 + this.mouvement.y * this.animation,
+            this.tailleSprite,
+            this.tailleSprite
         );
-	}
+    }
 }
 
-window.onload = function() {
-	var canvas = document.getElementById('canvas')
-	var ctx = canvas.getContext('2d')
-	var fromage = document.getElementById("fromage");
-    var sourisSprites = document.getElementById("souris");
-    var tuiles = {}
-    tuiles[TYPE.MUR] = document.getElementById("mur")
-    tuiles[TYPE.SOL] = document.getElementById("sol")
-    tuiles[TYPE.PAS] = document.getElementById("pas")
+window.onload = function () {
+    var canvas = document.getElementById('canvas');
+    var ctx = canvas.getContext('2d');
+    var fromage = document.getElementById('fromage');
+    var sourisSprites = document.getElementById('souris');
+    var tuiles = {};
+    tuiles[TYPE.MUR] = document.getElementById('mur');
+    tuiles[TYPE.SOL] = document.getElementById('sol');
+    tuiles[TYPE.PAS] = document.getElementById('pas');
 
-    var touchesPressees = new this.Set()
+    var touchesPressees = new this.Set();
 
-    var largeur = Math.floor(window.innerWidth / TAILLE_TUILE)
-    largeur = largeur - ((largeur+1) % 2)
-    var hauteur = Math.floor(window.innerHeight / TAILLE_TUILE)
-    hauteur = hauteur - ((hauteur+1) % 2)
+    var largeur = Math.floor(window.innerWidth / TAILLE_TUILE);
+    largeur = largeur - ((largeur + 1) % 2);
+    var hauteur = Math.floor(window.innerHeight / TAILLE_TUILE);
+    hauteur = hauteur - ((hauteur + 1) % 2);
 
-	canvas.width  = largeur * TAILLE_TUILE;
-	canvas.height = hauteur * TAILLE_TUILE;
-	
-    var labyrinthe = new Labyrinthe(largeur, hauteur, ctx, tuiles)
-    var souris = new Souris(labyrinthe.positionInitiale, ctx, sourisSprites)
-    
-    window.onkeydown = function(event) {
+    canvas.width = largeur * TAILLE_TUILE;
+    canvas.height = hauteur * TAILLE_TUILE;
+
+    var labyrinthe = new Labyrinthe(largeur, hauteur, ctx, tuiles);
+    var souris = new Souris(labyrinthe.positionInitiale, ctx, sourisSprites);
+
+    window.onkeydown = function (event) {
         if (event.key in ACTIONS) {
-            touchesPressees.add(event.key)
-            return false
+            touchesPressees.add(event.key);
+            return false;
         } else {
-            return true
+            return true;
         }
-    }
-    
-    window.onkeyup = function(event) {
+    };
+
+    window.onkeyup = function (event) {
         if (event.key in ACTIONS) {
-            touchesPressees.delete(event.key)
-            return false
+            touchesPressees.delete(event.key);
+            return false;
         } else {
-            return true
+            return true;
         }
-    }
-    
-    var timerID
-    timerID = setInterval(function() {
-        if (touchesPressees.size > 0) souris.animationSprite = (souris.animationSprite + 1) % 3
+    };
+
+    var timerID;
+    timerID = setInterval(function () {
+        if (touchesPressees.size > 0) souris.animationSprite = (souris.animationSprite + 1) % 3;
         if (souris.mouvement != MOUVEMENT.ARRET) {
-            souris.animation += 5
+            souris.animation += 5;
             if (souris.animation >= TAILLE_TUILE) {
-                souris.animation = 0
-                souris.position = souris.futurePosition
-                if (souris.position.x == labyrinthe.positionFinale.x && souris.position.y == labyrinthe.positionFinale.y) {
-                    window.alert("Miam miam !")
-                    clearInterval(timerID)
+                souris.animation = 0;
+                souris.position = souris.futurePosition;
+                if (
+                    souris.position.x == labyrinthe.positionFinale.x &&
+                    souris.position.y == labyrinthe.positionFinale.y
+                ) {
+                    window.alert('Miam miam !');
+                    clearInterval(timerID);
                 }
             }
         }
         if (souris.animation == 0) {
-            souris.mouvement = MOUVEMENT.ARRET
+            souris.mouvement = MOUVEMENT.ARRET;
             for (touche of Array.from(touchesPressees).reverse()) {
-                if (souris.bouger(touche, labyrinthe)) break
+                if (souris.bouger(touche, labyrinthe)) break;
             }
         }
 
-        labyrinthe.dessiner()
-	    dessinerTuile(ctx, fromage, labyrinthe.positionFinale.x, labyrinthe.positionFinale.y)
-	    souris.dessiner()
+        labyrinthe.dessiner();
+        dessinerTuile(ctx, fromage, labyrinthe.positionFinale.x, labyrinthe.positionFinale.y);
+        souris.dessiner();
     }, 40);
-}
+
+    if ('serviceWorker' in navigator) {
+        navigator.serviceWorker.register('service-worker.js');
+    }
+};
diff --git a/manifest.json b/manifest.json
new file mode 100644
index 0000000..5d0bed7
--- /dev/null
+++ b/manifest.json
@@ -0,0 +1,42 @@
+{
+  "short_name": "Labyrinthe",
+  "name": "Labyrinthe",
+  "description": "Trouveras-tu le fromage ?",
+  "icons": [
+    {
+      "src": "mur.png",
+      "type": "image/png",
+      "sizes": "15x15"
+    },
+    {
+      "src": "thumbnail.png",
+      "type": "image/png",
+      "sizes": "250x250"
+    }
+  ],
+  "start_url": "index.html",
+  "background_color": "#c55818",
+  "display": "standalone",
+  "scope": "index.html",
+  "theme_color": "#c55818",
+  "shortcuts": [
+    {
+      "name": "Labyrinthe",
+      "short_name": "Labyrinthe",
+      "description": "Trouveras-tu le fromage ?",
+      "url": "index.html",
+      "icons": [
+        {
+            "src": "mur.png",
+            "type": "image/png",
+            "sizes": "15x15"
+        },
+        {
+            "src": "thumbnail.png",
+            "type": "image/png",
+            "sizes": "250x250"
+        }
+      ]
+    }
+  ]
+}
diff --git a/mur.png b/mur.png
old mode 100644
new mode 100755
diff --git a/pas.png b/pas.png
new file mode 100755
index 0000000..a139c92
Binary files /dev/null and b/pas.png differ
diff --git a/service-worker.js b/service-worker.js
new file mode 100644
index 0000000..b3e69ed
--- /dev/null
+++ b/service-worker.js
@@ -0,0 +1,86 @@
+/*
+Copyright 2015, 2019, 2020 Google LLC. All Rights Reserved.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+ http://www.apache.org/licenses/LICENSE-2.0
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+// Incrementing OFFLINE_VERSION will kick off the install event and force
+// previously cached resources to be updated from the network.
+const OFFLINE_VERSION = 1;
+const CACHE_NAME = "offline";
+// Customize this with a different URL if needed.
+const OFFLINE_URL = "index.html";
+
+self.addEventListener("install", (event) => {
+  event.waitUntil(
+    (async () => {
+      const cache = await caches.open(CACHE_NAME);
+      // Setting {cache: 'reload'} in the new request will ensure that the
+      // response isn't fulfilled from the HTTP cache; i.e., it will be from
+      // the network.
+      await cache.add(new Request(OFFLINE_URL, { cache: "reload" }));
+    })()
+  );
+  // Force the waiting service worker to become the active service worker.
+  self.skipWaiting();
+});
+
+self.addEventListener("activate", (event) => {
+  event.waitUntil(
+    (async () => {
+      // Enable navigation preload if it's supported.
+      // See https://developers.google.com/web/updates/2017/02/navigation-preload
+      if ("navigationPreload" in self.registration) {
+        await self.registration.navigationPreload.enable();
+      }
+    })()
+  );
+
+  // Tell the active service worker to take control of the page immediately.
+  self.clients.claim();
+});
+
+self.addEventListener("fetch", (event) => {
+  // We only want to call event.respondWith() if this is a navigation request
+  // for an HTML page.
+  if (event.request.mode === "navigate") {
+    event.respondWith(
+      (async () => {
+        try {
+          // First, try to use the navigation preload response if it's supported.
+          const preloadResponse = await event.preloadResponse;
+          if (preloadResponse) {
+            return preloadResponse;
+          }
+
+          // Always try the network first.
+          const networkResponse = await fetch(event.request);
+          return networkResponse;
+        } catch (error) {
+          // catch is only triggered if an exception is thrown, which is likely
+          // due to a network error.
+          // If fetch() returns a valid HTTP response with a response code in
+          // the 4xx or 5xx range, the catch() will NOT be called.
+          console.log("Fetch failed; returning offline page instead.", error);
+
+          const cache = await caches.open(CACHE_NAME);
+          const cachedResponse = await cache.match(OFFLINE_URL);
+          return cachedResponse;
+        }
+      })()
+    );
+  }
+
+  // If our if() condition is false, then this fetch handler won't intercept the
+  // request. If there are any other fetch handlers registered, they will get a
+  // chance to call event.respondWith(). If no fetch handlers call
+  // event.respondWith(), the request will be handled by the browser as if there
+  // were no service worker involvement.
+});
diff --git a/sol.png b/sol.png
new file mode 100755
index 0000000..276b8ba
Binary files /dev/null and b/sol.png differ
diff --git a/souris.png b/souris.png
new file mode 100755
index 0000000..aff65a1
Binary files /dev/null and b/souris.png differ
diff --git a/style.css b/style.css
old mode 100644
new mode 100755
index b444332..11539a5
--- a/style.css
+++ b/style.css
@@ -1,4 +1,5 @@
 body {
+    background: #c55818;
     background-image: url("mur.png");
     background-position: center; 
     margin: 0;
@@ -7,4 +8,4 @@ body {
 canvas {
     display: block;
     margin: 0 auto;
-}
\ No newline at end of file
+}