diff --git a/app.js b/app.js
index 5a028f6..9a86960 100644
--- a/app.js
+++ b/app.js
@@ -209,6 +209,74 @@ document.getElementById('debug-toggle').addEventListener('click', () => {
}
});
+// === GUESTBOOK ===
+const GUESTBOOK_KEY = 'nexus_guestbook';
+const GUESTBOOK_MAX = 20;
+
+/**
+ * Load guestbook entries from localStorage.
+ * @returns {Array<{name: string, msg: string, ts: number}>}
+ */
+function guestbookLoad() {
+ try {
+ return JSON.parse(localStorage.getItem(GUESTBOOK_KEY) || '[]');
+ } catch (_) {
+ return [];
+ }
+}
+
+/**
+ * Save an entry to localStorage (max GUESTBOOK_MAX entries, newest first).
+ * @param {string} name
+ * @param {string} msg
+ */
+function guestbookSave(name, msg) {
+ const entries = guestbookLoad();
+ entries.unshift({ name: name.trim().slice(0, 32), msg: msg.trim().slice(0, 140), ts: Date.now() });
+ localStorage.setItem(GUESTBOOK_KEY, JSON.stringify(entries.slice(0, GUESTBOOK_MAX)));
+}
+
+/**
+ * Render guestbook entries into the messages container.
+ */
+function guestbookRender() {
+ const container = document.getElementById('guestbook-messages');
+ const entries = guestbookLoad();
+ if (entries.length === 0) {
+ container.innerHTML = '
No messages yet. Be the first!
';
+ return;
+ }
+ container.innerHTML = entries.map(e => {
+ const safeName = e.name ? e.name.replace(/&/g, '&').replace(/${safeName}
${safeMsg}
`;
+ }).join('');
+}
+
+const guestbookPanel = document.getElementById('guestbook-panel');
+const guestbookBtn = document.getElementById('guestbook-btn');
+const guestbookClose = document.getElementById('guestbook-close');
+const guestbookForm = document.getElementById('guestbook-form');
+
+guestbookBtn.addEventListener('click', () => {
+ guestbookRender();
+ guestbookPanel.classList.toggle('open');
+});
+
+guestbookClose.addEventListener('click', () => {
+ guestbookPanel.classList.remove('open');
+});
+
+guestbookForm.addEventListener('submit', (e) => {
+ e.preventDefault();
+ const name = /** @type {HTMLInputElement} */ (document.getElementById('guestbook-name')).value;
+ const msg = /** @type {HTMLTextAreaElement} */ (document.getElementById('guestbook-msg')).value.trim();
+ if (!msg) return;
+ guestbookSave(name, msg);
+ guestbookForm.reset();
+ guestbookRender();
+});
+
// === WEBSOCKET CLIENT ===
import { wsClient } from './ws-client.js';
diff --git a/index.html b/index.html
index 26344f3..4db0fbb 100644
--- a/index.html
+++ b/index.html
@@ -41,6 +41,26 @@
[Tab] to exit
+
+
+
+
+
+
+