From: Benjamin Auder <benjamin.auder@somewhere>
Date: Mon, 11 Jul 2022 20:29:24 +0000 (+0200)
Subject: Get rid of livereload dependency. Draft Baroque (still some issues)
X-Git-Url: https://git.auder.net/variants/current/doc/mini-custom.min.css?a=commitdiff_plain;h=0e466aac11288f35b34d744b2652c7b4e9df2e24;p=xogo.git

Get rid of livereload dependency. Draft Baroque (still some issues)
---

diff --git a/README.md b/README.md
index 4846e80..d478093 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,8 @@ Simplified version of old vchess.club, to focus on the essential : the game.
 
 ## Requirements (dev)
 
-Global npm install: nodemon, livereload. <br>
-A static web server like "php -S localhost:8000".
+PHP + Node.js + npm.
+```npm i -g nodemon```
 
 ## Usage
 
@@ -14,8 +14,6 @@ Rename parameters.js.dist &rarr; parameters.js, and edit file. <br>
 ```npm i```
 
 Generate some pieces: <br>
-```python generateSVG.py``` in pieces/Avalam
+```python generateSVG.py``` in variants/Avalam/pieces
 
-```./start.sh``` (edit 'php -S ...' line if necessary) <br>
-... <br>
-```./stop.sh```
+```./start.sh``` (and later, ```./stop.sh```)
diff --git a/TODO b/TODO
index e703843..40446da 100644
--- a/TODO
+++ b/TODO
@@ -1,7 +1,8 @@
 Baroque Berolina Bicolour Brotherhood
 For Baroque (and Fugue and...) --> maybe a dedicated parent class ?
 
-Go game with option oneColor
+Go game with option oneColor (révélée à la fin phase counting -->).
+Endgame :: mode "counting", déplacements libres (indépendamment de chaque coté)
 
 add variants :
 Dark Racing Kings ? Checkered-Teleport ?
diff --git a/app.js b/app.js
index 12c2b7a..a8f447b 100644
--- a/app.js
+++ b/app.js
@@ -390,6 +390,10 @@ const messageCenter = (msg) => {
     case "closerematch":
       toggleVisible("newGame");
       break;
+    case "filechange":
+      // TODO?: could be more subtle
+      location.reload();
+      break;
   }
 };
 
diff --git a/base_rules.js b/base_rules.js
index 2d08bd6..4627eb7 100644
--- a/base_rules.js
+++ b/base_rules.js
@@ -1341,7 +1341,13 @@ export default class ChessRules {
   }
 
   getStepSpec(color, x, y, piece) {
-    return this.pieces(color, x, y)[piece || this.getPieceType(x, y)];
+    let pieceType = piece;
+    const allSpecs = this.pieces(color, x, y);
+    if (!piece)
+      pieceType = this.getPieceType(x, y);
+    else if (allSpecs[piece].moveas)
+      pieceType = allSpecs[piece].moveas;
+    return allSpecs[pieceType];
   }
 
   // Can thing on square1 capture thing on square2?
diff --git a/package-lock.json b/package-lock.json
index 7f52ea0..c06d32b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -6,6 +6,195 @@
     "": {
       "dependencies": {
         "ws": "^7.5.3"
+      },
+      "devDependencies": {
+        "chokidar": "^3.5.3"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "dev": true,
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "dev": true,
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true,
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
       }
     },
     "node_modules/ws": {
@@ -30,6 +219,132 @@
     }
   },
   "dependencies": {
+    "anymatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
+      "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
+      "dev": true,
+      "requires": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      }
+    },
+    "binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "dev": true
+    },
+    "braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dev": true,
+      "requires": {
+        "fill-range": "^7.0.1"
+      }
+    },
+    "chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "dev": true,
+      "requires": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "fsevents": "~2.3.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      }
+    },
+    "fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dev": true,
+      "requires": {
+        "to-regex-range": "^5.0.1"
+      }
+    },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "optional": true
+    },
+    "glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dev": true,
+      "requires": {
+        "is-glob": "^4.0.1"
+      }
+    },
+    "is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dev": true,
+      "requires": {
+        "binary-extensions": "^2.0.0"
+      }
+    },
+    "is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true
+    },
+    "is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "requires": {
+        "is-extglob": "^2.1.1"
+      }
+    },
+    "is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "dev": true
+    },
+    "normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "dev": true
+    },
+    "picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "dev": true
+    },
+    "readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dev": true,
+      "requires": {
+        "picomatch": "^2.2.1"
+      }
+    },
+    "to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dev": true,
+      "requires": {
+        "is-number": "^7.0.0"
+      }
+    },
     "ws": {
       "version": "7.5.5",
       "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.5.tgz",
diff --git a/package.json b/package.json
index b02fc5e..79387df 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,12 @@
 {
   "dependencies": {
     "ws": "^7.5.3"
+  },
+  "devDependencies": {
+    "chokidar": "^3.5.3"
+  },
+  "scripts": {
+    "start": "./start.sh",
+    "stop": "./stop.sh"
   }
 }
diff --git a/parameters.js.dist b/parameters.js.dist
index c1e3eb5..564bd7c 100644
--- a/parameters.js.dist
+++ b/parameters.js.dist
@@ -6,6 +6,7 @@ const Params = {
 
   // Usage on (socket) server:
   socket_port: 8080, //...
+  dev: true,
 
   // Usage on both:
   socket_path: "/ws",
diff --git a/server.js b/server.js
index e08d13b..06d9866 100644
--- a/server.js
+++ b/server.js
@@ -55,7 +55,13 @@ wss.on("connection", (socket, req) => {
   sockets[sid] = socket;
   socket.isAlive = true;
   socket.on("pong", () => socket.isAlive = true);
-
+  if (params.dev == true) {
+    const chokidar = require("chokidar");
+    const watcher = chokidar.watch(
+      ["*.js", "*.css", "utils/", "variants/"],
+      {persistent: true});
+    watcher.on("change", path => send(sid, "filechange", {path: path}));
+  }
   socket.on("message", (msg) => {
     const obj = JSON.parse(msg);
     switch (obj.code) {
diff --git a/start.sh b/start.sh
index 4fe6790..8434097 100755
--- a/start.sh
+++ b/start.sh
@@ -1,10 +1,5 @@
 #!/bin/sh
 
-nodemon -i index.js -i base_rules.js ./server.js &
-echo "NODE_PID=$!" > .pid
-
-# NOTE: require browser plugin + start it
-livereload -e 'html,js,css,png,jpg,jpeg,gif,svg' -w 1000 -d . &
-
-# I use 8080 for socket and 8000 for http server (arbitrary...)
+nodemon -i app.js -i base_rules.js ./server.js &
+echo $! > .pid
 php -S localhost:8000 &
diff --git a/stop.sh b/stop.sh
index 8d54dcc..dee6895 100755
--- a/stop.sh
+++ b/stop.sh
@@ -1,5 +1,6 @@
 #!/bin/sh
 
 # https://stackoverflow.com/questions/13939038/how-do-you-run-a-command-for-each-line-of-a-file
-source ./.pid
-kill -9 -`ps p $NODE_PID -o pgid | grep "[0-9]\+" | tr -d " "`
+while read pid; do
+  kill -9 -`ps p $pid -o pgid | grep "[0-9]\+" | tr -d " "`
+done <.pid
diff --git a/variants.js b/variants.js
index 8fe9d95..e5df230 100644
--- a/variants.js
+++ b/variants.js
@@ -17,7 +17,7 @@ const variants = [
 //  {name: 'Balaklava', desc: 'Meet the Mammoth'},
   {name: 'Bario', desc: 'A quantum story'},
   {name: "Balanced", desc: "balanced chess"},
-//  {name: 'Baroque', desc: 'Exotic captures'},*/
+  {name: 'Baroque', desc: 'Exotic captures'},
   {name: "Benedict", desc: "Change colors"},
 //  {name: 'Berolina', desc: 'Pawns move diagonally'},
 //  {name: 'Bicolour', desc: 'Harassed kings'},
diff --git a/pieces/Alapo/black_CIRCLE.svg b/variants/Alapo/pieces/black_CIRCLE.svg
similarity index 100%
rename from pieces/Alapo/black_CIRCLE.svg
rename to variants/Alapo/pieces/black_CIRCLE.svg
diff --git a/pieces/Alapo/black_SQUARE.svg b/variants/Alapo/pieces/black_SQUARE.svg
similarity index 100%
rename from pieces/Alapo/black_SQUARE.svg
rename to variants/Alapo/pieces/black_SQUARE.svg
diff --git a/pieces/Alapo/black_TRIANGLE.svg b/variants/Alapo/pieces/black_TRIANGLE.svg
similarity index 100%
rename from pieces/Alapo/black_TRIANGLE.svg
rename to variants/Alapo/pieces/black_TRIANGLE.svg
diff --git a/pieces/Alapo/black_TRIANGLE_inv.svg b/variants/Alapo/pieces/black_TRIANGLE_inv.svg
similarity index 100%
rename from pieces/Alapo/black_TRIANGLE_inv.svg
rename to variants/Alapo/pieces/black_TRIANGLE_inv.svg
diff --git a/pieces/Alapo/black_circle.svg b/variants/Alapo/pieces/black_circle.svg
similarity index 100%
rename from pieces/Alapo/black_circle.svg
rename to variants/Alapo/pieces/black_circle.svg
diff --git a/pieces/Alapo/black_square.svg b/variants/Alapo/pieces/black_square.svg
similarity index 100%
rename from pieces/Alapo/black_square.svg
rename to variants/Alapo/pieces/black_square.svg
diff --git a/pieces/Alapo/black_triangle.svg b/variants/Alapo/pieces/black_triangle.svg
similarity index 100%
rename from pieces/Alapo/black_triangle.svg
rename to variants/Alapo/pieces/black_triangle.svg
diff --git a/pieces/Alapo/black_triangle_inv.svg b/variants/Alapo/pieces/black_triangle_inv.svg
similarity index 100%
rename from pieces/Alapo/black_triangle_inv.svg
rename to variants/Alapo/pieces/black_triangle_inv.svg
diff --git a/pieces/Alapo/white_CIRCLE.svg b/variants/Alapo/pieces/white_CIRCLE.svg
similarity index 100%
rename from pieces/Alapo/white_CIRCLE.svg
rename to variants/Alapo/pieces/white_CIRCLE.svg
diff --git a/pieces/Alapo/white_SQUARE.svg b/variants/Alapo/pieces/white_SQUARE.svg
similarity index 100%
rename from pieces/Alapo/white_SQUARE.svg
rename to variants/Alapo/pieces/white_SQUARE.svg
diff --git a/pieces/Alapo/white_TRIANGLE.svg b/variants/Alapo/pieces/white_TRIANGLE.svg
similarity index 100%
rename from pieces/Alapo/white_TRIANGLE.svg
rename to variants/Alapo/pieces/white_TRIANGLE.svg
diff --git a/pieces/Alapo/white_TRIANGLE_inv.svg b/variants/Alapo/pieces/white_TRIANGLE_inv.svg
similarity index 100%
rename from pieces/Alapo/white_TRIANGLE_inv.svg
rename to variants/Alapo/pieces/white_TRIANGLE_inv.svg
diff --git a/pieces/Alapo/white_circle.svg b/variants/Alapo/pieces/white_circle.svg
similarity index 100%
rename from pieces/Alapo/white_circle.svg
rename to variants/Alapo/pieces/white_circle.svg
diff --git a/pieces/Alapo/white_square.svg b/variants/Alapo/pieces/white_square.svg
similarity index 100%
rename from pieces/Alapo/white_square.svg
rename to variants/Alapo/pieces/white_square.svg
diff --git a/pieces/Alapo/white_triangle.svg b/variants/Alapo/pieces/white_triangle.svg
similarity index 100%
rename from pieces/Alapo/white_triangle.svg
rename to variants/Alapo/pieces/white_triangle.svg
diff --git a/pieces/Alapo/white_triangle_inv.svg b/variants/Alapo/pieces/white_triangle_inv.svg
similarity index 100%
rename from pieces/Alapo/white_triangle_inv.svg
rename to variants/Alapo/pieces/white_triangle_inv.svg
diff --git a/variants/Alapo/style.css b/variants/Alapo/style.css
index 4fbefb1..7a18a55 100644
--- a/variants/Alapo/style.css
+++ b/variants/Alapo/style.css
@@ -1,49 +1,49 @@
 piece.black.rook {
-  background-image: url('/pieces/Alapo/black_SQUARE.svg');
+  background-image: url('/variants/Alapo/pieces/black_SQUARE.svg');
 }
 piece.black.bishop {
-  background-image: url('/pieces/Alapo/black_TRIANGLE.svg');
+  background-image: url('/variants/Alapo/pieces/black_TRIANGLE.svg');
 }
 piece.black.bishop_inv {
-  background-image: url('/pieces/Alapo/black_TRIANGLE_inv.svg');
+  background-image: url('/variants/Alapo/pieces/black_TRIANGLE_inv.svg');
 }
 piece.black.queen {
-  background-image: url('/pieces/Alapo/black_CIRCLE.svg');
+  background-image: url('/variants/Alapo/pieces/black_CIRCLE.svg');
 }
 piece.black.babyrook {
-  background-image: url('/pieces/Alapo/black_square.svg');
+  background-image: url('/variants/Alapo/pieces/black_square.svg');
 }
 piece.black.babybishop {
-  background-image: url('/pieces/Alapo/black_triangle.svg');
+  background-image: url('/variants/Alapo/pieces/black_triangle.svg');
 }
 piece.black.babybishop_inv {
-  background-image: url('/pieces/Alapo/black_triangle_inv.svg');
+  background-image: url('/variants/Alapo/pieces/black_triangle_inv.svg');
 }
 piece.black.babyqueen {
-  background-image: url('/pieces/Alapo/black_circle.svg');
+  background-image: url('/variants/Alapo/pieces/black_circle.svg');
 }
 
 piece.white.rook {
-  background-image: url('/pieces/Alapo/white_SQUARE.svg');
+  background-image: url('/variants/Alapo/pieces/white_SQUARE.svg');
 }
 piece.white.bishop {
-  background-image: url('/pieces/Alapo/white_TRIANGLE.svg');
+  background-image: url('/variants/Alapo/pieces/white_TRIANGLE.svg');
 }
 piece.white.bishop_inv {
-  background-image: url('/pieces/Alapo/white_TRIANGLE_inv.svg');
+  background-image: url('/variants/Alapo/pieces/white_TRIANGLE_inv.svg');
 }
 piece.white.queen {
-  background-image: url('/pieces/Alapo/white_CIRCLE.svg');
+  background-image: url('/variants/Alapo/pieces/white_CIRCLE.svg');
 }
 piece.white.babyrook {
-  background-image: url('/pieces/Alapo/white_square.svg');
+  background-image: url('/variants/Alapo/pieces/white_square.svg');
 }
 piece.white.babybishop {
-  background-image: url('/pieces/Alapo/white_triangle.svg');
+  background-image: url('/variants/Alapo/pieces/white_triangle.svg');
 }
 piece.white.babybishop_inv {
-  background-image: url('/pieces/Alapo/white_triangle_inv.svg');
+  background-image: url('/variants/Alapo/pieces/white_triangle_inv.svg');
 }
 piece.white.babyqueen {
-  background-image: url('/pieces/Alapo/white_circle.svg');
+  background-image: url('/variants/Alapo/pieces/white_circle.svg');
 }
diff --git a/pieces/Ambiguous/red_target.svg b/variants/Ambiguous/pieces/red_target.svg
similarity index 100%
rename from pieces/Ambiguous/red_target.svg
rename to variants/Ambiguous/pieces/red_target.svg
diff --git a/pieces/Ambiguous/yellow_target.svg b/variants/Ambiguous/pieces/yellow_target.svg
similarity index 100%
rename from pieces/Ambiguous/yellow_target.svg
rename to variants/Ambiguous/pieces/yellow_target.svg
diff --git a/variants/Antiking1/style.css b/variants/Antiking1/style.css
index a6ffda1..faf34b7 100644
--- a/variants/Antiking1/style.css
+++ b/variants/Antiking1/style.css
@@ -1,8 +1,8 @@
 @import url("/variants/_Antiking/style.css");
 
 piece.black.pawn {
-  background-image: url('/pieces/Berolina/black_pawn.svg');
+  background-image: url('/variants/Berolina/pieces/black_pawn.svg');
 }
 piece.white.pawn {
-  background-image: url('/pieces/Berolina/white_pawn.svg');
+  background-image: url('/variants/Berolina/pieces/white_pawn.svg');
 }
diff --git a/variants/Apocalypse/rules.html b/variants/Apocalypse/rules.html
index 211ad8c..6674bb2 100644
--- a/variants/Apocalypse/rules.html
+++ b/variants/Apocalypse/rules.html
@@ -8,6 +8,8 @@
 
 <p>The goal is to eliminate all enemy pawns.</p>
 
-<a href="/variants/Apocalypse/complete_rules.html">Full rules description.</a>
+<a target="_blank" href="/variants/Apocalypse/complete_rules.html">
+  Full rules description.
+</a>
 
 <p class="author">C.S. Elliott (1976).</p>
diff --git a/variants/Atarigo/style.css b/variants/Atarigo/style.css
index c72abda..d38ff8e 100644
--- a/variants/Atarigo/style.css
+++ b/variants/Atarigo/style.css
@@ -3,9 +3,9 @@
 }
 
 piece.white.stone {
-  background-image: url('/pieces/Go/black_stone.svg');
+  background-image: url('/variants/Go/pieces/black_stone.svg');
 }
 
 piece.black.stone {
-  background-image: url('/pieces/Go/white_stone.svg');
+  background-image: url('/variants/Go/pieces/white_stone.svg');
 }
diff --git a/pieces/Avalam/.gitignore b/variants/Avalam/pieces/.gitignore
similarity index 100%
rename from pieces/Avalam/.gitignore
rename to variants/Avalam/pieces/.gitignore
diff --git a/pieces/Avalam/generateSVG.py b/variants/Avalam/pieces/generateSVG.py
similarity index 100%
rename from pieces/Avalam/generateSVG.py
rename to variants/Avalam/pieces/generateSVG.py
diff --git a/variants/Avalam/style.css b/variants/Avalam/style.css
index 04463d1..ed6279c 100644
--- a/variants/Avalam/style.css
+++ b/variants/Avalam/style.css
@@ -1,33 +1,33 @@
 piece.white.stack {
-  background-image: url('/pieces/Avalam/white_stack.svg');
+  background-image: url('/variants/Avalam/pieces/white_stack.svg');
 }
 piece.white.stack2 {
-  background-image: url('/pieces/Avalam/white_stack2.svg');
+  background-image: url('/variants/Avalam/pieces/white_stack2.svg');
 }
 piece.white.stack3 {
-  background-image: url('/pieces/Avalam/white_stack3.svg');
+  background-image: url('/variants/Avalam/pieces/white_stack3.svg');
 }
 piece.white.stack4 {
-  background-image: url('/pieces/Avalam/white_stack4.svg');
+  background-image: url('/variants/Avalam/pieces/white_stack4.svg');
 }
 piece.white.stack5 {
-  background-image: url('/pieces/Avalam/white_stack5.svg');
+  background-image: url('/variants/Avalam/pieces/white_stack5.svg');
 }
 
 piece.black.stack {
-  background-image: url('/pieces/Avalam/black_stack.svg');
+  background-image: url('/variants/Avalam/pieces/black_stack.svg');
 }
 piece.black.stack2 {
-  background-image: url('/pieces/Avalam/black_stack2.svg');
+  background-image: url('/variants/Avalam/pieces/black_stack2.svg');
 }
 piece.black.stack3 {
-  background-image: url('/pieces/Avalam/black_stack3.svg');
+  background-image: url('/variants/Avalam/pieces/black_stack3.svg');
 }
 piece.black.stack4 {
-  background-image: url('/pieces/Avalam/black_stack4.svg');
+  background-image: url('/variants/Avalam/pieces/black_stack4.svg');
 }
 piece.black.stack5 {
-  background-image: url('/pieces/Avalam/black_stack5.svg');
+  background-image: url('/variants/Avalam/pieces/black_stack5.svg');
 }
 
 .board-sq {
diff --git a/variants/Bario/class.js b/variants/Bario/class.js
index 603aded..01cb3d7 100644
--- a/variants/Bario/class.js
+++ b/variants/Bario/class.js
@@ -6,7 +6,8 @@ export default class BarioRules extends ChessRules {
 
   static get Options() {
     return {
-      // TODO: Zen too?
+      select: C.Options.select,
+      input: C.Options.input,
       styles: [
         "atomic", "cannibal", "capture", "cylinder",
         "dark", "madrasi", "rifle", "teleport"
diff --git a/variants/Baroque/class.js b/variants/Baroque/class.js
new file mode 100644
index 0000000..62904e8
--- /dev/null
+++ b/variants/Baroque/class.js
@@ -0,0 +1,402 @@
+import ChessRules from "/base_rules.js";
+import GiveawayRules from "/variants/Giveaway/class.js";
+import {Random} from "/utils/alea.js";
+import PiPo from "/utils/PiPo.js";
+import Move from "/utils/Move.js";
+
+export default class BaroqueRules extends ChessRules {
+
+  static get Options() {
+    return {
+      select: C.Options.Select,
+      input: [
+        {
+          label: "Capture king",
+          variable: "taking",
+          type: "checkbox",
+          defaut: false
+        }
+      ],
+      styles: [
+        "balance",
+        "capture",
+        "crazyhouse",
+        "cylinder",
+        "doublemove",
+        "progressive",
+        "recycle",
+        "teleport"
+      ]
+    };
+  }
+
+  get hasFlags() {
+    return false;
+  }
+  get hasEnpassant() {
+    return false;
+  }
+
+  genRandInitBaseFen() {
+    if (this.options["randomness"] == 0)
+      return "rnbkqbnm/pppppppp/8/8/8/8/PPPPPPPP/MNBQKBNR";
+    const options = Object.assign({mode: "suicide"}, this.options);
+    const gr = new GiveawayRules({options: options, genFenOnly: true});
+    let res = gr.genRandInitBaseFen();
+    let immPos = {};
+    for (let c of ['w', 'b']) {
+      const rookChar = (c == 'w' ? 'R' : 'r');
+      switch (Random.randInt(2)) {
+        case 0:
+          immPos[c] = res.fen.indexOf(rookChar);
+          break;
+        case 1:
+          immPos[c] = res.fen.lastIndexOf(rookChar);
+          break;
+      }
+    }
+    res.fen = res.fen.substring(0, immPos['b']) + 'i' +
+              res.fen.substring(immPos['b'] + 1, immPos['w']) + 'I' +
+              res.fen.substring(immPos['w'] + 1);
+    return res;
+  }
+
+  // Although other pieces keep their names here for coding simplicity,
+  // keep in mind that:
+  //  - a "rook" is a coordinator, capturing by coordinating with the king
+  //  - a "knight" is a long-leaper, capturing as in draughts
+  //  - a "bishop" is a chameleon, capturing as its prey
+  //  - a "queen" is a withdrawer, capturing by moving away from pieces
+
+  pieces() {
+    return Object.assign({},
+      super.pieces(),
+      {
+        'p': {
+          "class": "pawn",
+          moves: [
+            {steps: [[0, 1], [0, -1], [1, 0], [-1, 0]]}
+          ]
+        },
+        'r': {
+          "class": "rook",
+          moves: [
+            {
+              steps: [
+                [1, 0], [0, 1], [-1, 0], [0, -1],
+                [1, 1], [1, -1], [-1, 1], [-1, -1]
+              ]
+            }
+          ]
+        },
+        'n': {
+          "class": "knight",
+          moveas: 'r'
+        },
+        'b': {
+          "class": "bishop",
+          moveas: 'r'
+        },
+        'q': {
+          "class": "queen",
+          moveas: 'r'
+        },
+        'i': {
+          "class": "immobilizer",
+          moveas: 'q'
+        }
+      }
+    );
+  }
+
+  // Is piece on square (x,y) immobilized?
+  isImmobilized([x, y]) {
+    const piece = this.getPiece(x, y);
+    const color = this.getColor(x, y);
+    const oppCol = C.GetOppCol(color);
+    const adjacentSteps = this.pieces()['k'].moves[0].steps;
+    for (let step of adjacentSteps) {
+      const [i, j] = [x + step[0], this.getY(y + step[1])];
+      if (
+        this.onBoard(i, j) &&
+        this.board[i][j] != "" &&
+        this.getColor(i, j) == oppCol
+      ) {
+        const oppPiece = this.getPiece(i, j);
+        if (oppPiece == 'i') {
+          // Moving is possible only if this immobilizer is neutralized
+          for (let step2 of adjacentSteps) {
+            const [i2, j2] = [i + step2[0], this.getY(j + step2[1])];
+            if (i2 == x && j2 == y)
+              continue; //skip initial piece!
+            if (
+              this.onBoard(i2, j2) &&
+              this.board[i2][j2] != "" &&
+              this.getColor(i2, j2) == color
+            ) {
+              if (['b', 'i'].includes(this.getPiece(i2, j2)))
+                return false;
+            }
+          }
+          return true; //immobilizer isn't neutralized
+        }
+        // Chameleons can't be immobilized twice,
+        // because there is only one immobilizer
+        if (oppPiece == 'b' && piece == 'i')
+          return true;
+      }
+    }
+    return false;
+  }
+
+  canTake([x1, y1], [x2, y2]) {
+    // Deactivate standard captures, except for king:
+    return (
+      this.getPiece(x1, y1) == 'k' &&
+      this.getColor(x1, y1) != this.getColor(x2, y2)
+    );
+  }
+
+  postProcessPotentialMoves(moves) {
+    if (moves.length == 0)
+      return [];
+    switch (moves[0].vanish[0].p) {
+      case 'p':
+        this.addPawnCaptures(moves);
+        break;
+      case 'r':
+        this.addRookCaptures(moves);
+        break;
+      case 'n':
+        const [x, y] = [moves[0].start.x, moves[0].start.y];
+        moves = moves.concat(this.getKnightCaptures([x, y]));
+        break;
+      case 'b':
+        moves = this.getBishopCaptures(moves);
+        break;
+      case 'q':
+        this.addPawnCaptures(moves);
+        break;
+    }
+    return moves;
+  }
+
+  // Modify capturing moves among listed pawn moves
+  addPawnCaptures(moves, byChameleon) {
+    const steps = this.pieces()['p'].moves[0].steps;
+    const color = this.turn;
+    const oppCol = C.GetOppCol(color);
+    moves.forEach(m => {
+      if (byChameleon && m.start.x != m.end.x && m.start.y != m.end.y)
+        // Chameleon not moving as pawn
+        return;
+      // Try capturing in every direction
+      for (let step of steps) {
+        const sq2 = [m.end.x + 2 * step[0], this.getY(m.end.y + 2 * step[1])];
+        if (
+          this.onBoard(sq2[0], sq2[1]) &&
+          this.board[sq2[0]][sq2[1]] != "" &&
+          this.getColor(sq2[0], sq2[1]) == color
+        ) {
+          // Potential capture
+          const sq1 = [m.end.x + step[0], this.getY(m.end.y + step[1])];
+          if (
+            this.board[sq1[0]][sq1[1]] != "" &&
+            this.getColor(sq1[0], sq1[1]) == oppCol
+          ) {
+            const piece1 = this.getPiece(sq1[0], sq1[1]);
+            if (!byChameleon || piece1 == 'p') {
+              m.vanish.push(
+                new PiPo({
+                  x: sq1[0],
+                  y: sq1[1],
+                  c: oppCol,
+                  p: piece1
+                })
+              );
+            }
+          }
+        }
+      }
+    });
+  }
+
+  addRookCaptures(moves, byChameleon) {
+    const color = this.turn;
+    const oppCol = V.GetOppCol(color);
+    const kp = this.searchKingPos(color)[0];
+    moves.forEach(m => {
+      // Check piece-king rectangle (if any) corners for enemy pieces
+      if (m.end.x == kp[0] || m.end.y == kp[1])
+        return; //"flat rectangle"
+      const corner1 = [m.end.x, kp[1]];
+      const corner2 = [kp[0], m.end.y];
+      for (let [i, j] of [corner1, corner2]) {
+        if (this.board[i][j] != "" && this.getColor(i, j) == oppCol) {
+          const piece = this.getPiece(i, j);
+          if (!byChameleon || piece == 'r') {
+            m.vanish.push(
+              new PiPo({
+                x: i,
+                y: j,
+                p: piece,
+                c: oppCol
+              })
+            );
+          }
+        }
+      }
+    });
+  }
+
+  getKnightCaptures(startSquare, byChameleon) {
+    // Look in every direction for captures
+    const steps = this.pieces()['r'].moves[0].steps;
+    const color = this.turn;
+    const oppCol = C.GetOppCol(color);
+    let moves = [];
+    const [x, y] = [startSquare[0], startSquare[1]];
+    const piece = this.getPiece(x, y); //might be a chameleon!
+    outerLoop: for (let step of steps) {
+      let [i, j] = [x + step[0], this.getY(y + step[1])];
+      while (this.onBoard(i, j) && this.board[i][j] == "")
+        [i, j] = [i + step[0], this.getY(j + step[1])];
+      if (
+        !this.onBoard(i, j) ||
+        this.getColor(i, j) == color ||
+        (byChameleon && this.getPiece(i, j) != 'n')
+      ) {
+        continue;
+      }
+      // last(thing), cur(thing) : stop if "cur" is our color,
+      // or beyond board limits, or if "last" isn't empty and cur neither.
+      // Otherwise, if cur is empty then add move until cur square;
+      // if cur is occupied then stop if !!byChameleon and the square not
+      // occupied by a leaper.
+      let last = [i, j];
+      let cur = [i + step[0], this.getY(j + step[1])];
+      let vanished = [new PiPo({x: x, y: y, c: color, p: piece})];
+      while (this.onBoard(cur[0], cur[1])) {
+        if (this.board[last[0]][last[1]] != "") {
+          const oppPiece = this.getPiece(last[0], last[1]);
+          if (!!byChameleon && oppPiece != 'n')
+            continue outerLoop;
+          // Something to eat:
+          vanished.push(
+            new PiPo({x: last[0], y: last[1], c: oppCol, p: oppPiece})
+          );
+        }
+        if (this.board[cur[0]][cur[1]] != "") {
+          if (
+            this.getColor(cur[0], cur[1]) == color ||
+            this.board[last[0]][last[1]] != ""
+          ) {
+            //TODO: redundant test
+            continue outerLoop;
+          }
+        }
+        else {
+          moves.push(
+            new Move({
+              appear: [new PiPo({x: cur[0], y: cur[1], c: color, p: piece})],
+              vanish: JSON.parse(JSON.stringify(vanished)), //TODO: required?
+              start: {x: x, y: y},
+              end: {x: cur[0], y: cur[1]}
+            })
+          );
+        }
+        last = [last[0] + step[0], this.getY(last[1] + step[1])];
+        cur = [cur[0] + step[0], this.getY(cur[1] + step[1])];
+      }
+    }
+    return moves;
+  }
+
+  // Chameleon
+  getBishopCaptures(moves) {
+    const [x, y] = [moves[0].start.x, moves[0].start.y];
+    moves = moves.concat(this.getKnightCaptures([x, y], "asChameleon"));
+    // No "king capture" because king cannot remain under check
+    this.addPawnCaptures(moves, "asChameleon");
+    this.addRookCaptures(moves, "asChameleon");
+    this.addQueenCaptures(moves, "asChameleon");
+    // Post-processing: merge similar moves, concatenating vanish arrays
+    let mergedMoves = {};
+    moves.forEach(m => {
+      const key = m.end.x + this.size.x * m.end.y;
+      if (!mergedMoves[key])
+        mergedMoves[key] = m;
+      else {
+        for (let i = 1; i < m.vanish.length; i++)
+          mergedMoves[key].vanish.push(m.vanish[i]);
+      }
+    });
+    return Object.values(mergedMoves);
+  }
+
+  addQueenCaptures(moves, byChameleon) {
+    if (moves.length == 0) return;
+    const [x, y] = [moves[0].start.x, moves[0].start.y];
+    const adjacentSteps = this.pieces()['r'].moves[0].steps;
+    let capturingDirections = [];
+    const color = this.turn;
+    const oppCol = C.GetOppCol(color);
+    adjacentSteps.forEach(step => {
+      const [i, j] = [x + step[0], this.getY(y + step[1])];
+      if (
+        this.onBoard(i, j) &&
+        this.board[i][j] != "" &&
+        this.getColor(i, j) == oppCol &&
+        (!byChameleon || this.getPiece(i, j) == 'q')
+      ) {
+        capturingDirections.push(step);
+      }
+    });
+    moves.forEach(m => {
+      const step = [
+        m.end.x != x ? (m.end.x - x) / Math.abs(m.end.x - x) : 0,
+        m.end.y != y ? (m.end.y - y) / Math.abs(m.end.y - y) : 0
+      ];
+      // NOTE: includes() and even _.isEqual() functions fail...
+      // TODO: this test should be done only once per direction
+      if (
+        capturingDirections.some(dir => {
+          return dir[0] == -step[0] && dir[1] == -step[1];
+        })
+      ) {
+        const [i, j] = [x - step[0], this.getY(y - step[1])];
+        m.vanish.push(
+          new PiPo({
+            x: i,
+            y: j,
+            p: this.getPiece(i, j),
+            c: oppCol
+          })
+        );
+      }
+    });
+  }
+
+  underAttack([x, y], oppCol) {
+    // Generate all potential opponent moves, check if king captured.
+    // TODO: do it more efficiently.
+    const color = this.getColor(x, y);
+    for (let i = 0; i < this.size.x; i++) {
+      for (let j = 0; j < this.size.y; j++) {
+        if (
+          this.board[i][j] != "" && this.getColor(i, j) == oppCol &&
+          this.getPotentialMovesFrom([i, j]).some(m => {
+            return (
+              m.vanish.length >= 2 &&
+              [1, m.vanish.length - 1].some(k => m.vanish[k].p == 'k')
+            );
+          })
+        ) {
+          return true;
+        }
+      }
+    }
+    return false;
+  }
+
+};
diff --git a/variants/Baroque/pieces/black_immobilizer.svg b/variants/Baroque/pieces/black_immobilizer.svg
new file mode 100644
index 0000000..fdc0ee5
--- /dev/null
+++ b/variants/Baroque/pieces/black_immobilizer.svg
@@ -0,0 +1,92 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="100%"
+   width="100%"
+   version="1.1"
+   viewBox="0 0 2048 2048"
+   id="svg44"
+   sodipodi:docname="bu.svg"
+   inkscape:version="0.92.2 2405546, 2018-03-11">
+  <metadata
+     id="metadata50">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs48" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="960"
+     inkscape:window-height="1060"
+     id="namedview46"
+     showgrid="false"
+     inkscape:zoom="0.11523438"
+     inkscape:cx="1041.3559"
+     inkscape:cy="1024"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg44" />
+  <path
+     style="color:#000000;display:block;fill:#000000;fill-rule:nonzero"
+     d="m 1161,1706 h 170 v 137 h 274 V 1468 L 1383,1297 V 819 L 1553,649 V 444 h 153 V 205 H 341 v 239 h 153 v 205 l 171,170 v 478 l -222,171 v 375 h 273 v -137 h 171 v 137 h 274 z M 564,460 V 358 h 920 v 102 z m 460,1092 H 512 v -46 l 73,-55 h 879 l 71,55 v 46 z m 0,-169 H 674 l 60,-47 v -57 h 580 v 57 l 60,47 z m 0,-546 H 734 v -46 l -60,-58 h 700 l -60,58 v 46 z m 0,-172 H 610 l -46,-43 v -58 h 920 v 58 l -46,43 z"
+     display="block"
+     id="path30"
+     inkscape:connector-curvature="0" />
+  <g
+     id="g42"
+     transform="matrix(1,0,0,-1,0,2048)"
+     style="fill:#ffffff;fill-rule:nonzero">
+    <path
+       style="color:#000000;display:block"
+       d="m 564,1588 v 102 h 920 v -102 z"
+       display="block"
+       id="path32"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1024,496 H 512 v 46 l 73,55 h 879 l 71,-55 v -46 z"
+       display="block"
+       id="path34"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1024,665 H 674 l 60,47 v 57 h 580 v -57 l 60,-47 z"
+       display="block"
+       id="path36"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1024,1211 H 734 v 46 l -60,58 h 700 l -60,-58 v -46 z"
+       display="block"
+       id="path38"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1024,1383 H 610 l -46,43 v 58 h 920 v -58 l -46,-43 z"
+       display="block"
+       id="path40"
+       inkscape:connector-curvature="0" />
+  </g>
+</svg>
diff --git a/variants/Baroque/pieces/white_immobilizer.svg b/variants/Baroque/pieces/white_immobilizer.svg
new file mode 100644
index 0000000..bf9f16a
--- /dev/null
+++ b/variants/Baroque/pieces/white_immobilizer.svg
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   height="100%"
+   width="100%"
+   version="1.1"
+   viewBox="0 0 2048 2048"
+   id="svg70"
+   sodipodi:docname="wu.svg"
+   inkscape:version="0.92.2 2405546, 2018-03-11">
+  <metadata
+     id="metadata76">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs
+     id="defs74" />
+  <sodipodi:namedview
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1"
+     objecttolerance="10"
+     gridtolerance="10"
+     guidetolerance="10"
+     inkscape:pageopacity="0"
+     inkscape:pageshadow="2"
+     inkscape:window-width="960"
+     inkscape:window-height="1060"
+     id="namedview72"
+     showgrid="false"
+     inkscape:zoom="0.11523438"
+     inkscape:cx="1041.3559"
+     inkscape:cy="1024"
+     inkscape:window-x="0"
+     inkscape:window-y="20"
+     inkscape:window-maximized="0"
+     inkscape:current-layer="svg70" />
+  <path
+     style="color:#000000;display:block;fill:#000000;fill-rule:nonzero"
+     d="m 1161,1706 h 170 v 137 h 274 V 1468 L 1383,1297 V 819 L 1553,649 V 444 h 153 V 205 H 341 v 239 h 153 v 205 l 171,170 v 478 l -222,171 v 375 h 273 v -137 h 171 v 137 h 274 z M 1639,376 H 409 V 273 H 1639 Z M 1484,580 H 564 V 444 h 920 z m -170,717 H 734 V 819 h 580 z m 222,239 v 239 h -137 v -137 h -308 v 137 H 956 V 1638 H 649 v 137 H 512 V 1536 Z M 1459,649 1356,751 H 693 L 588,649 Z m -110,716 127,103 H 572 l 128,-103 z"
+     display="block"
+     id="path54"
+     inkscape:connector-curvature="0" />
+  <g
+     id="g64"
+     transform="matrix(1,0,0,-1,0,2048)"
+     style="fill:#ffffff;fill-rule:nonzero">
+    <path
+       style="color:#000000;display:block"
+       d="M 1639,1672 H 409 v 103 h 1230 z"
+       display="block"
+       id="path56"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1484,1468 H 564 v 136 h 920 z"
+       display="block"
+       id="path58"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1314,751 H 734 v 478 h 580 z"
+       display="block"
+       id="path60"
+       inkscape:connector-curvature="0" />
+    <path
+       style="color:#000000;display:block"
+       d="M 1536,512 V 273 H 1399 V 410 H 1091 V 273 H 956 V 410 H 649 V 273 H 512 v 239 z"
+       display="block"
+       id="path62"
+       inkscape:connector-curvature="0" />
+  </g>
+  <path
+     style="color:#000000;display:block;fill:#ffffff;fill-rule:nonzero"
+     d="M 1459,649 1356,751 H 693 L 588,649 Z"
+     display="block"
+     id="path66"
+     inkscape:connector-curvature="0" />
+  <path
+     style="color:#000000;display:block;fill:#ffffff;fill-rule:nonzero"
+     d="m 1349,1365 127,103 H 572 l 128,-103 z"
+     display="block"
+     id="path68"
+     inkscape:connector-curvature="0" />
+</svg>
diff --git a/variants/Baroque/rules.html b/variants/Baroque/rules.html
new file mode 100644
index 0000000..c65158e
--- /dev/null
+++ b/variants/Baroque/rules.html
@@ -0,0 +1 @@
+<p>TODO</p>
diff --git a/variants/Baroque/style.css b/variants/Baroque/style.css
new file mode 100644
index 0000000..1fd6566
--- /dev/null
+++ b/variants/Baroque/style.css
@@ -0,0 +1,8 @@
+@import url("/base_pieces.css");
+
+piece.white.immobilizer {
+  background-image: url('/variants/Baroque/pieces/white_immobilizer.svg');
+}
+piece.black.immobilizer {
+  background-image: url('/variants/Baroque/pieces/black_immobilizer.svg');
+}
diff --git a/pieces/Benedict/CREDITS b/variants/Benedict/pieces/CREDITS
similarity index 100%
rename from pieces/Benedict/CREDITS
rename to variants/Benedict/pieces/CREDITS
diff --git a/pieces/Benedict/black_cleopatra.svg b/variants/Benedict/pieces/black_cleopatra.svg
similarity index 100%
rename from pieces/Benedict/black_cleopatra.svg
rename to variants/Benedict/pieces/black_cleopatra.svg
diff --git a/pieces/Benedict/black_cleopatra_TODO.svg b/variants/Benedict/pieces/black_cleopatra_TODO.svg
similarity index 100%
rename from pieces/Benedict/black_cleopatra_TODO.svg
rename to variants/Benedict/pieces/black_cleopatra_TODO.svg
diff --git a/pieces/Benedict/white_cleopatra.svg b/variants/Benedict/pieces/white_cleopatra.svg
similarity index 100%
rename from pieces/Benedict/white_cleopatra.svg
rename to variants/Benedict/pieces/white_cleopatra.svg
diff --git a/pieces/Benedict/white_cleopatra_TODO.svg b/variants/Benedict/pieces/white_cleopatra_TODO.svg
similarity index 100%
rename from pieces/Benedict/white_cleopatra_TODO.svg
rename to variants/Benedict/pieces/white_cleopatra_TODO.svg
diff --git a/variants/Benedict/style.css b/variants/Benedict/style.css
index 0923e9e..31e16b6 100644
--- a/variants/Benedict/style.css
+++ b/variants/Benedict/style.css
@@ -1,9 +1,8 @@
 @import url("/base_pieces.css");
 
 piece.black.cleopatra {
-  background-image: url('/pieces/Benedict/black_cleopatra.svg');
+  background-image: url('/variants/Benedict/pieces/black_cleopatra.svg');
 }
-
 piece.white.cleopatra {
-  background-image: url('/pieces/Benedict/white_cleopatra.svg');
+  background-image: url('/variants/Benedict/pieces/white_cleopatra.svg');
 }
diff --git a/pieces/Berolina/CREDITS b/variants/Berolina/pieces/CREDITS
similarity index 100%
rename from pieces/Berolina/CREDITS
rename to variants/Berolina/pieces/CREDITS
diff --git a/pieces/Berolina/black_pawn.svg b/variants/Berolina/pieces/black_pawn.svg
similarity index 100%
rename from pieces/Berolina/black_pawn.svg
rename to variants/Berolina/pieces/black_pawn.svg
diff --git a/pieces/Berolina/white_pawn.svg b/variants/Berolina/pieces/white_pawn.svg
similarity index 100%
rename from pieces/Berolina/white_pawn.svg
rename to variants/Berolina/pieces/white_pawn.svg
diff --git a/pieces/Chakart/CREDITS b/variants/Chakart/pieces/CREDITS
similarity index 100%
rename from pieces/Chakart/CREDITS
rename to variants/Chakart/pieces/CREDITS
diff --git a/pieces/Chakart/banana.svg b/variants/Chakart/pieces/banana.svg
similarity index 100%
rename from pieces/Chakart/banana.svg
rename to variants/Chakart/pieces/banana.svg
diff --git a/pieces/Chakart/bomb.svg b/variants/Chakart/pieces/bomb.svg
similarity index 100%
rename from pieces/Chakart/bomb.svg
rename to variants/Chakart/pieces/bomb.svg
diff --git a/pieces/Chakart/egg.svg b/variants/Chakart/pieces/egg.svg
similarity index 100%
rename from pieces/Chakart/egg.svg
rename to variants/Chakart/pieces/egg.svg
diff --git a/pieces/Chakart/mushroom.svg b/variants/Chakart/pieces/mushroom.svg
similarity index 100%
rename from pieces/Chakart/mushroom.svg
rename to variants/Chakart/pieces/mushroom.svg
diff --git a/pieces/Chakart/shell.svg b/variants/Chakart/pieces/shell.svg
similarity index 100%
rename from pieces/Chakart/shell.svg
rename to variants/Chakart/pieces/shell.svg
diff --git a/variants/Chakart/rules.html b/variants/Chakart/rules.html
index 4b88248..d45cb0d 100644
--- a/variants/Chakart/rules.html
+++ b/variants/Chakart/rules.html
@@ -10,6 +10,8 @@
   <li>Eggs hide either a bonus or malus: see full description.</li>
 </ul>
 
-<a href="/variants/Chakart/complete_rules.html">Full rules description.</a>
+<a target="_blank" href="/variants/Chakart/complete_rules.html">
+  Full rules description.
+</a>
 
 <p class="author">Charlotte Blard &amp; Benjamin Auder (2020).</p>
diff --git a/variants/Chakart/style.css b/variants/Chakart/style.css
index 6f45bed..819fe51 100644
--- a/variants/Chakart/style.css
+++ b/variants/Chakart/style.css
@@ -1,19 +1,19 @@
 @import url("/base_pieces.css");
 
 piece.egg {
-  background-image: url('/pieces/Chakart/egg.svg');
+  background-image: url('/variants/Chakart/pieces/egg.svg');
 }
 
 piece.mushroom {
-  background-image: url('/pieces/Chakart/mushroom.svg');
+  background-image: url('/variants/Chakart/pieces/mushroom.svg');
 }
 
 piece.banana {
-  background-image: url('/pieces/Chakart/banana.svg');
+  background-image: url('/variants/Chakart/pieces/banana.svg');
 }
 
 piece.bomb {
-  background-image: url('/pieces/Chakart/bomb.svg');
+  background-image: url('/variants/Chakart/pieces/bomb.svg');
 }
 
 piece.white.invisible {
@@ -29,7 +29,7 @@ piece.immobilized {
 }
 
 piece.remote-capture {
-  background-image: url('/pieces/Chakart/shell.svg');
+  background-image: url('/variants/Chakart/pieces/shell.svg');
 }
 
 piece.white.mystery {
diff --git a/pieces/Go/CREDITS b/variants/Go/pieces/CREDITS
similarity index 100%
rename from pieces/Go/CREDITS
rename to variants/Go/pieces/CREDITS
diff --git a/pieces/Go/black_stone.svg b/variants/Go/pieces/black_stone.svg
similarity index 100%
rename from pieces/Go/black_stone.svg
rename to variants/Go/pieces/black_stone.svg
diff --git a/pieces/Go/white_stone.svg b/variants/Go/pieces/white_stone.svg
similarity index 100%
rename from pieces/Go/white_stone.svg
rename to variants/Go/pieces/white_stone.svg
diff --git a/pieces/Antiking/black_antiking.svg b/variants/_Antiking/pieces/black_antiking.svg
similarity index 100%
rename from pieces/Antiking/black_antiking.svg
rename to variants/_Antiking/pieces/black_antiking.svg
diff --git a/pieces/Antiking/white_antiking.svg b/variants/_Antiking/pieces/white_antiking.svg
similarity index 100%
rename from pieces/Antiking/white_antiking.svg
rename to variants/_Antiking/pieces/white_antiking.svg
diff --git a/variants/_Antiking/style.css b/variants/_Antiking/style.css
index 3dfe37e..cdbab55 100644
--- a/variants/_Antiking/style.css
+++ b/variants/_Antiking/style.css
@@ -1,8 +1,8 @@
 @import url("/base_pieces.css");
 
 piece.black.antiking {
-  background-image: url('/pieces/Antiking/black_antiking.svg');
+  background-image: url('/variants/_Antiking/pieces/black_antiking.svg');
 }
 piece.white.antiking {
-  background-image: url('/pieces/Antiking/white_antiking.svg');
+  background-image: url('/variants/_Antiking/pieces/white_antiking.svg');
 }