diff --git a/html-client/package.json b/html-client/package.json
old mode 100755
new mode 100644
index 509f17a9..2911f2fa
--- a/html-client/package.json
+++ b/html-client/package.json
@@ -21,6 +21,7 @@
"keymaster": "^1.6.2",
"lodash": "^4.17.11",
"parcel": "^1.12.3",
+ "particles.js": "^2.0.0",
"phaser": "^3.15.1",
"preact": "^8.3.1",
"preact-redux": "^2.0.3",
diff --git a/html-client/src/components/cryp.list.container.js b/html-client/src/components/cryp.list.container.js
new file mode 100644
index 00000000..6ae16e7a
--- /dev/null
+++ b/html-client/src/components/cryp.list.container.js
@@ -0,0 +1,20 @@
+const { connect } = require('preact-redux');
+
+const CrypList = require('./cryp.list.component');
+const actions = require('./../actions');
+
+const addState = connect(
+ function receiveState(state) {
+ const { ws, cryps, selectedCryps } = state;
+ return { cryps, selectedCryps };
+ },
+
+ function receiveDispatch(dispatch) {
+ function setSelectedCryps(crypIds) {
+ dispatch(actions.setSelectedCryps(crypIds));
+ }
+ return { setSelectedCryps };
+ }
+);
+
+module.exports = addState(CrypList);
diff --git a/html-client/src/components/game.container.js b/html-client/src/components/game.container.js
new file mode 100644
index 00000000..64149b37
--- /dev/null
+++ b/html-client/src/components/game.container.js
@@ -0,0 +1,51 @@
+const { connect } = require('preact-redux');
+
+const actions = require('../actions');
+
+const Game = require('./game.component');
+
+const addState = connect(
+ function receiveState(state) {
+ const { ws, game, account, activeSkill, activeIncoming } = state;
+
+ function selectSkillTarget(targetCrypId) {
+ if (activeSkill) {
+ return ws.sendGameSkill(game.id, activeSkill.crypId, targetCrypId, activeSkill.skill);
+ }
+ return false;
+ }
+
+ // intercept self casting skills
+ if (activeSkill && activeSkill.skill.self_targeting) {
+ ws.sendGameSkill(game.id, activeSkill.crypId, null, activeSkill.skill.skill);
+ }
+
+ function selectIncomingTarget(crypId) {
+ if (activeIncoming) {
+ return ws.sendGameTarget(game.id, crypId, activeIncoming);
+ }
+ return false;
+ }
+
+ return { game, account, activeSkill, activeIncoming, selectSkillTarget, selectIncomingTarget };
+ },
+
+ function receiveDispatch(dispatch) {
+ function setActiveSkill(crypId, skill) {
+ dispatch(actions.setActiveSkill(crypId, skill));
+ }
+
+ function setActiveIncoming(skillId) {
+ dispatch(actions.setActiveIncoming(skillId));
+ }
+
+ function quit() {
+ dispatch(actions.setGame(null));
+ }
+
+ return { setActiveSkill, setActiveIncoming, quit };
+ }
+
+);
+
+module.exports = addState(Game);
diff --git a/html-client/src/components/header.component.jsx b/html-client/src/components/header.component.jsx
index 3dd2be8b..938fa6d6 100644
--- a/html-client/src/components/header.component.jsx
+++ b/html-client/src/components/header.component.jsx
@@ -1,7 +1,7 @@
// eslint-disable-next-line
const preact = require('preact');
-
const LoginContainer = require('./login.container');
+const ParticleContainer = require('./particles.container');
function renderHeader() {
return (
@@ -10,8 +10,10 @@ function renderHeader() {
cryps.gg