diff --git a/client/index.html b/client/index.html
index 3b8dd6f..1d1f17b 100644
--- a/client/index.html
+++ b/client/index.html
@@ -37,10 +37,6 @@
-
-
-
-
diff --git a/client/public/version.js b/client/public/version.js
index ebbc482..d0fe5a5 100644
--- a/client/public/version.js
+++ b/client/public/version.js
@@ -1,5 +1,5 @@
// Maintainer-controlled web client version.
// Format: YYYY.MM.DD Rn (example: 2026.02.20 R2)
-window.CHGRID_WEB_VERSION = "2026.02.25 R243";
+window.CHGRID_WEB_VERSION = "2026.02.25 R244";
// Optional display timezone for timestamps. Falls back to America/Detroit if unset/invalid.
window.CHGRID_TIME_ZONE = "America/Detroit";
diff --git a/client/src/main.ts b/client/src/main.ts
index 0f9dfcd..d6143fa 100644
--- a/client/src/main.ts
+++ b/client/src/main.ts
@@ -56,7 +56,7 @@ import {
import { createItemPropertyEditor } from './items/itemPropertyEditor';
import { createItemPropertyPresentation } from './items/itemPropertyPresentation';
import { ItemBehaviorRegistry } from './items/types/behaviorRegistry';
-import { NICKNAME_STORAGE_KEY, SettingsStore } from './settings/settingsStore';
+import { SettingsStore } from './settings/settingsStore';
import { runConnectFlow, runDisconnectFlow, type ConnectFlowDeps } from './session/connectionFlow';
import { MediaSession } from './session/mediaSession';
import { type AudioLayerState } from './types/audio';
@@ -102,8 +102,6 @@ type Dom = {
updatesSection: HTMLElement;
updatesToggle: HTMLButtonElement;
updatesPanel: HTMLDivElement;
- nicknameContainer: HTMLDivElement;
- preconnectNickname: HTMLInputElement;
connectButton: HTMLButtonElement;
logoutButton: HTMLButtonElement;
disconnectButton: HTMLButtonElement;
@@ -135,8 +133,6 @@ const dom: Dom = {
updatesSection: requiredById('updatesSection'),
updatesToggle: requiredById('updatesToggle'),
updatesPanel: requiredById('updatesPanel'),
- nicknameContainer: requiredById('nicknameContainer'),
- preconnectNickname: requiredById('preconnectNickname'),
connectButton: requiredById('connectButton'),
logoutButton: requiredById('logoutButton'),
disconnectButton: requiredById('disconnectButton'),
@@ -519,6 +515,7 @@ function sanitizeAuthUsername(value: string): string {
function updateConnectAvailability(): void {
dom.logoutButton.disabled = !authSessionToken.trim() && !state.running;
if (state.running) {
+ dom.connectButton.textContent = 'Connect';
dom.connectButton.disabled = true;
dom.loginView.classList.add('hidden');
dom.registerView.classList.add('hidden');
@@ -532,6 +529,7 @@ function updateConnectAvailability(): void {
const hasRegisterCredentials =
sanitizeAuthUsername(dom.registerUsername.value).length >= 2 && dom.registerPassword.value.trim().length >= 8;
const authReady = hasSessionToken || (authMode === 'login' ? hasLoginCredentials : hasRegisterCredentials);
+ dom.connectButton.textContent = hasSessionToken ? 'Connect' : authMode === 'login' ? 'Log In & Connect' : 'Register & Connect';
dom.connectButton.disabled = mediaSession.isConnecting() || !authReady;
}
@@ -1419,8 +1417,6 @@ async function handleAuthResult(message: Extract audio.sfxUiBlip(),
audioUiConfirm: () => audio.sfxUiConfirm(),
audioUiCancel: () => audio.sfxUiCancel(),
- NICKNAME_STORAGE_KEY,
getCarriedItemId: () => getCarriedItem()?.id ?? null,
recomputeActiveItemPropertyKeys,
itemPropertyLabel,
@@ -2558,8 +2553,6 @@ function closeSettings(): void {
function setupUiHandlers(): void {
setupDomUiHandlers({
dom,
- sanitizeName,
- nicknameStorageKey: NICKNAME_STORAGE_KEY,
updateConnectAvailability,
connect,
disconnect,
@@ -2615,11 +2608,6 @@ setupInputHandlers();
setupUiHandlers();
dom.authUsername.value = sanitizeAuthUsername(authUsername);
dom.registerUsername.value = sanitizeAuthUsername(authUsername);
-const storedNickname = sanitizeName(settings.loadNickname());
-dom.preconnectNickname.value = storedNickname;
-if (storedNickname) {
- state.player.nickname = storedNickname;
-}
setAuthMode('login');
updateConnectAvailability();
updateDeviceSummary();
diff --git a/client/src/network/messageHandlers.ts b/client/src/network/messageHandlers.ts
index 7a7ff78..f0815c5 100644
--- a/client/src/network/messageHandlers.ts
+++ b/client/src/network/messageHandlers.ts
@@ -25,13 +25,11 @@ type MessageHandlerDeps = {
carriedItemId: string | null;
};
dom: {
- nicknameContainer: HTMLElement;
connectButton: HTMLElement;
disconnectButton: HTMLElement;
focusGridButton: HTMLElement;
canvas: HTMLCanvasElement;
instructions: HTMLElement;
- preconnectNickname: HTMLInputElement;
};
signalingSend: (message: unknown) => void;
peerManager: {
@@ -63,7 +61,6 @@ type MessageHandlerDeps = {
audioUiBlip: () => void;
audioUiConfirm: () => void;
audioUiCancel: () => void;
- NICKNAME_STORAGE_KEY: string;
getCarriedItemId: () => string | null;
recomputeActiveItemPropertyKeys: (itemId: string) => void;
itemPropertyLabel: (key: string) => string;
@@ -113,7 +110,6 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
const targetY = persistedPosition?.y ?? message.player.y;
deps.state.player.x = Math.max(0, Math.min(deps.getWorldGridSize() - 1, targetX));
deps.state.player.y = Math.max(0, Math.min(deps.getWorldGridSize() - 1, targetY));
- deps.dom.nicknameContainer.classList.add('hidden');
deps.dom.connectButton.classList.add('hidden');
deps.dom.disconnectButton.classList.remove('hidden');
deps.dom.focusGridButton.classList.remove('hidden');
@@ -228,8 +224,8 @@ export function createOnMessageHandler(deps: MessageHandlerDeps): (message: Inco
case 'nickname_result': {
deps.state.player.nickname = deps.sanitizeName(message.effectiveNickname) || 'user...';
if (message.accepted) {
- deps.dom.preconnectNickname.value = deps.state.player.nickname;
- localStorage.setItem(deps.NICKNAME_STORAGE_KEY, deps.state.player.nickname);
+ deps.updateStatus(`Nickname set to ${deps.state.player.nickname}`);
+ deps.audioUiConfirm();
} else {
deps.pushChatMessage(message.reason || 'Nickname unavailable.');
deps.audioUiCancel();
diff --git a/client/src/session/connectionFlow.ts b/client/src/session/connectionFlow.ts
index d33b244..cf6f49e 100644
--- a/client/src/session/connectionFlow.ts
+++ b/client/src/session/connectionFlow.ts
@@ -3,8 +3,6 @@ import type { GameState } from '../state/gameState';
const WELCOME_TIMEOUT_MS = 8_000;
type DomRefs = {
- preconnectNickname: HTMLInputElement;
- nicknameContainer: HTMLDivElement;
connectButton: HTMLButtonElement;
disconnectButton: HTMLButtonElement;
focusGridButton: HTMLButtonElement;
@@ -40,15 +38,14 @@ export type ConnectFlowDeps = {
};
/**
- * Runs connect flow: validate nickname, preflight mic/device setup, then signaling connect.
+ * Runs connect flow: preflight media setup, then signaling connect/auth.
*/
export async function runConnectFlow(deps: ConnectFlowDeps): Promise {
if (deps.mediaIsConnecting() || deps.state.running) {
return;
}
- const nickname = deps.sanitizeName(deps.dom.preconnectNickname.value);
+ const nickname = deps.sanitizeName(deps.state.player.nickname);
deps.state.player.nickname = nickname || deps.state.player.nickname;
- deps.dom.preconnectNickname.value = nickname;
if (nickname) {
deps.settingsSaveNickname(nickname);
}
@@ -138,7 +135,6 @@ export function runDisconnectFlow(deps: ConnectFlowDeps): void {
deps.state.effectSelectIndex = 0;
deps.mediaSetConnecting(false);
- deps.dom.nicknameContainer.classList.remove('hidden');
deps.dom.connectButton.classList.remove('hidden');
deps.dom.disconnectButton.classList.add('hidden');
deps.dom.focusGridButton.classList.add('hidden');
diff --git a/client/src/ui/domBindings.ts b/client/src/ui/domBindings.ts
index 0e8af6e..0c88f3b 100644
--- a/client/src/ui/domBindings.ts
+++ b/client/src/ui/domBindings.ts
@@ -3,7 +3,6 @@
*/
type UiDom = {
connectButton: HTMLButtonElement;
- preconnectNickname: HTMLInputElement;
disconnectButton: HTMLButtonElement;
focusGridButton: HTMLButtonElement;
settingsButton: HTMLButtonElement;
@@ -19,8 +18,6 @@ type UiDom = {
*/
type UiBindingsDeps = {
dom: UiDom;
- sanitizeName: (value: string) => string;
- nicknameStorageKey: string;
updateConnectAvailability: () => void;
connect: () => Promise;
disconnect: () => void;
@@ -46,25 +43,6 @@ export function setupUiHandlers(deps: UiBindingsDeps): void {
deps.dom.connectButton.addEventListener('click', () => {
void deps.connect();
});
- deps.dom.preconnectNickname.addEventListener('input', () => {
- deps.updateConnectAvailability();
- });
- deps.dom.preconnectNickname.addEventListener('change', () => {
- const clean = deps.sanitizeName(deps.dom.preconnectNickname.value);
- deps.dom.preconnectNickname.value = clean;
- if (clean) {
- localStorage.setItem(deps.nicknameStorageKey, clean);
- } else {
- localStorage.removeItem(deps.nicknameStorageKey);
- }
- deps.updateConnectAvailability();
- });
- deps.dom.preconnectNickname.addEventListener('keydown', (event) => {
- if (event.key === 'Enter' && !deps.dom.connectButton.disabled) {
- event.preventDefault();
- void deps.connect();
- }
- });
deps.dom.disconnectButton.addEventListener('click', () => {
deps.disconnect();
diff --git a/deploy/scripts/up.sh b/deploy/scripts/up.sh
index d59671c..eca875b 100644
--- a/deploy/scripts/up.sh
+++ b/deploy/scripts/up.sh
@@ -5,6 +5,9 @@ REPO_ROOT="${1:-/home/bestmidi/chgrid}"
PUBLISH_DIR="${2:-/home/bestmidi/public_html/chgrid}"
BASE_PATH="${3:-/chgrid/}"
SERVICE_NAME="${4:-chat-grid.service}"
+if [[ -z "${SERVICE_NAME// }" || "$SERVICE_NAME" == "-" || "$SERVICE_NAME" == ".service" ]]; then
+ SERVICE_NAME="chat-grid.service"
+fi
"$REPO_ROOT/deploy/scripts/deploy_client.sh" "$REPO_ROOT" "$PUBLISH_DIR" "$BASE_PATH"
sudo systemctl restart "$SERVICE_NAME"