Multiplayer needs a free Firebase Realtime Database. Once set up, this stays a single static HTML file on GitHub Pages.
console.firebase.google.com and click Add project.</> icon). Skip hosting.firebaseConfig = {…} snippet.index.html, find the FIREBASE CONFIG block (near the top of the <script> section) and paste your config replacing the empty object. Commit, push.{
"rules": {
"rooms": {
"$code": {
".read": "auth != null",
".write": "auth != null && !data.exists() && newData.child('hostId').val() === auth.uid",
".validate": "$code.matches(/^[A-Z0-9]{4,5}$/)",
"hostId": { ".write": "auth != null && (data.val() === auth.uid || root.child('rooms/'+$code+'/players/'+data.val()+'/status').val() === 'gone' || !root.child('rooms/'+$code+'/players/'+data.val()).exists())" },
"status": { ".write": "auth != null && auth.uid === root.child('rooms/'+$code+'/hostId').val()", ".validate": "newData.isString() && newData.val().length < 16" },
"board": { ".write": "auth != null && auth.uid === root.child('rooms/'+$code+'/hostId').val()" },
"round": { ".write": "auth != null && auth.uid === root.child('rooms/'+$code+'/hostId').val()" },
"startTime": { ".write": "auth != null && auth.uid === root.child('rooms/'+$code+'/hostId').val()" },
"endTime": { ".write": "auth != null && auth.uid === root.child('rooms/'+$code+'/hostId').val()" },
"createdAt": { ".write": "auth != null && !data.exists()" },
"settings": {
".write": "auth != null && auth.uid === root.child('rooms/'+$code+'/hostId').val()",
"size": { ".validate": "newData.isNumber() && newData.val() >= 3 && newData.val() <= 8" },
"timer": { ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 1800" },
"minLen": { ".validate": "newData.isNumber() && newData.val() >= 3 && newData.val() <= 8" }
},
"players": {
"$pid": {
".write": "auth != null && auth.uid === $pid",
"name": { ".validate": "newData.isString() && newData.val().length <= 24" }
}
},
"rounds": {
"$r": {
"foundBy": {
"$pid": {
".write": "auth != null && auth.uid === $pid",
"$word": { ".validate": "$word.length <= 16 && newData.child('len').isNumber()" }
}
}
}
}
}
}
}
}