diff --git a/client/index.html b/client/index.html
index c7de718..d20c926 100644
--- a/client/index.html
+++ b/client/index.html
@@ -42,6 +42,10 @@
+
diff --git a/client/public/version.js b/client/public/version.js
index 2bc04bc..a2d7d4f 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 R248";
+window.CHGRID_WEB_VERSION = "2026.02.25 R249";
// 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 34364ac..58b0449 100644
--- a/client/src/main.ts
+++ b/client/src/main.ts
@@ -100,6 +100,8 @@ type Dom = {
registerPasswordConfirm: HTMLInputElement;
registerEmail: HTMLInputElement;
authPolicyHintRegister: HTMLParagraphElement;
+ authSessionView: HTMLElement;
+ authSessionText: HTMLParagraphElement;
showRegisterButton: HTMLButtonElement;
showLoginButton: HTMLButtonElement;
updatesSection: HTMLElement;
@@ -133,6 +135,8 @@ const dom: Dom = {
registerPasswordConfirm: requiredById('registerPasswordConfirm'),
registerEmail: requiredById('registerEmail'),
authPolicyHintRegister: requiredById('authPolicyHintRegister'),
+ authSessionView: requiredById('authSessionView'),
+ authSessionText: requiredById('authSessionText'),
showRegisterButton: requiredById('showRegisterButton'),
showLoginButton: requiredById('showLoginButton'),
updatesSection: requiredById('updatesSection'),
@@ -587,10 +591,20 @@ function updateConnectAvailability(): void {
dom.connectButton.disabled = true;
dom.loginView.classList.add('hidden');
dom.registerView.classList.add('hidden');
+ dom.authSessionView.classList.add('hidden');
return;
}
- dom.loginView.classList.toggle('hidden', authMode !== 'login');
- dom.registerView.classList.toggle('hidden', authMode !== 'register');
+ if (hasSessionToken) {
+ const label = sanitizeAuthUsername(authUsername) || 'current account';
+ dom.authSessionText.textContent = `Logged in as ${label}.`;
+ dom.loginView.classList.add('hidden');
+ dom.registerView.classList.add('hidden');
+ dom.authSessionView.classList.remove('hidden');
+ } else {
+ dom.loginView.classList.toggle('hidden', authMode !== 'login');
+ dom.registerView.classList.toggle('hidden', authMode !== 'register');
+ dom.authSessionView.classList.add('hidden');
+ }
const usernameMin = authPolicy?.usernameMinLength ?? 1;
const passwordMin = authPolicy?.passwordMinLength ?? 1;
const hasLoginCredentials =
@@ -1115,8 +1129,9 @@ function formatCoordinate(value: number): string {
/** Persists current local player coordinates for reconnect/refresh restore. */
function persistPlayerPosition(): void {
try {
+ const positionKey = getPlayerPositionStorageKey();
localStorage.setItem(
- 'spatialChatPosition',
+ positionKey,
JSON.stringify({ x: state.player.x, y: state.player.y }),
);
} catch {
@@ -1126,7 +1141,7 @@ function persistPlayerPosition(): void {
/** Loads previously persisted local player coordinates, when available and valid. */
function getPersistedPlayerPosition(): { x: number; y: number } | null {
- const raw = localStorage.getItem('spatialChatPosition');
+ const raw = localStorage.getItem(getPlayerPositionStorageKey());
if (!raw) return null;
try {
const parsed = JSON.parse(raw) as { x?: unknown; y?: unknown };
@@ -1138,6 +1153,12 @@ function getPersistedPlayerPosition(): { x: number; y: number } | null {
}
}
+/** Resolves local storage key for per-account saved player position. */
+function getPlayerPositionStorageKey(): string {
+ const usernameKey = sanitizeAuthUsername(authUsername);
+ return usernameKey ? `spatialChatPosition:${usernameKey}` : 'spatialChatPosition';
+}
+
/** Picks one random footstep sample URL. */
function randomFootstepUrl(): string {
return FOOTSTEP_SOUND_URLS[Math.floor(Math.random() * FOOTSTEP_SOUND_URLS.length)];
diff --git a/client/src/styles.css b/client/src/styles.css
index 623bffd..633fbec 100644
--- a/client/src/styles.css
+++ b/client/src/styles.css
@@ -123,6 +123,11 @@ body {
font-size: 0.92rem;
}
+#authSessionText {
+ margin: 0;
+ color: #cbd5e1;
+}
+
.nickname-row {
display: flex;
justify-content: center;