Compare commits

...

2 Commits

Author SHA1 Message Date
Alexander Whitestone
1420c0d64b WIP: Claude Code progress on #833
Some checks are pending
CI / validate (pull_request) Waiting to run
Automated salvage commit — agent session ended (exit 0).
Work in progress, may need continuation.
2026-04-06 13:51:57 -04:00
Alexander Whitestone
49fbc50035 feat: add /help page for Nexus web frontend
Some checks are pending
CI / validate (pull_request) Waiting to run
Adds help.html to the repo root, resolving the 404 at /help for users
accessing the Nexus web app. The page documents navigation controls,
keyboard bindings, Timmy chat commands, portal status indicators, and
HUD panel descriptions, using the existing dark-space/holographic design
system (Orbitron + JetBrains Mono, teal/purple palette).

Also adds tests/test_help_page.py to verify the page exists and covers
required sections.

Fixes #833

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-06 13:50:18 -04:00
3 changed files with 530 additions and 0 deletions

488
help.html Normal file
View File

@@ -0,0 +1,488 @@
<!DOCTYPE html>
<!--
THE NEXUS — Help Page
Refs: #833 (Missing /help page)
Design: dark space / holographic — matches Nexus design system
-->
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Help — The Nexus</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@300;400;500;600&family=Orbitron:wght@400;600;700&display=swap" rel="stylesheet">
<style>
:root {
--color-bg: #050510;
--color-surface: rgba(10, 15, 40, 0.85);
--color-border: rgba(74, 240, 192, 0.2);
--color-border-bright: rgba(74, 240, 192, 0.5);
--color-text: #e0f0ff;
--color-text-muted: #8a9ab8;
--color-primary: #4af0c0;
--color-primary-dim: rgba(74, 240, 192, 0.12);
--color-secondary: #7b5cff;
--color-danger: #ff4466;
--color-warning: #ffaa22;
--font-display: 'Orbitron', sans-serif;
--font-body: 'JetBrains Mono', monospace;
--panel-blur: 16px;
--panel-radius: 8px;
--transition: 200ms cubic-bezier(0.16, 1, 0.3, 1);
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body {
background: var(--color-bg);
font-family: var(--font-body);
color: var(--color-text);
min-height: 100vh;
padding: 32px 16px 64px;
}
/* === STARFIELD BG === */
body::before {
content: '';
position: fixed;
inset: 0;
background:
radial-gradient(ellipse at 20% 20%, rgba(74,240,192,0.03) 0%, transparent 50%),
radial-gradient(ellipse at 80% 80%, rgba(123,92,255,0.04) 0%, transparent 50%);
pointer-events: none;
z-index: 0;
}
.page-wrap {
position: relative;
z-index: 1;
max-width: 720px;
margin: 0 auto;
}
/* === HEADER === */
.page-header {
margin-bottom: 32px;
padding-bottom: 20px;
border-bottom: 1px solid var(--color-border);
}
.back-link {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 11px;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--color-text-muted);
text-decoration: none;
margin-bottom: 20px;
transition: color var(--transition);
}
.back-link:hover { color: var(--color-primary); }
.page-title {
font-family: var(--font-display);
font-size: 28px;
font-weight: 700;
letter-spacing: 0.1em;
color: var(--color-text);
line-height: 1.2;
}
.page-title span { color: var(--color-primary); }
.page-subtitle {
margin-top: 8px;
font-size: 13px;
color: var(--color-text-muted);
line-height: 1.5;
}
/* === SECTIONS === */
.help-section {
background: var(--color-surface);
border: 1px solid var(--color-border);
border-radius: var(--panel-radius);
overflow: hidden;
margin-bottom: 20px;
backdrop-filter: blur(var(--panel-blur));
}
.section-header {
padding: 14px 20px;
border-bottom: 1px solid var(--color-border);
background: linear-gradient(90deg, rgba(74,240,192,0.04) 0%, transparent 100%);
display: flex;
align-items: center;
gap: 10px;
}
.section-icon {
font-size: 14px;
opacity: 0.8;
}
.section-title {
font-family: var(--font-display);
font-size: 12px;
font-weight: 600;
letter-spacing: 0.15em;
text-transform: uppercase;
color: var(--color-primary);
}
.section-body {
padding: 16px 20px;
}
/* === KEY BINDING TABLE === */
.key-table {
width: 100%;
border-collapse: collapse;
}
.key-table tr + tr td {
border-top: 1px solid rgba(74,240,192,0.07);
}
.key-table td {
padding: 8px 0;
font-size: 12px;
line-height: 1.5;
vertical-align: top;
}
.key-table td:first-child {
width: 140px;
padding-right: 16px;
}
.key-group {
display: flex;
flex-wrap: wrap;
gap: 4px;
}
kbd {
display: inline-block;
font-family: var(--font-body);
font-size: 10px;
font-weight: 600;
letter-spacing: 0.05em;
background: rgba(74,240,192,0.08);
border: 1px solid rgba(74,240,192,0.3);
border-bottom-width: 2px;
border-radius: 4px;
padding: 2px 7px;
color: var(--color-primary);
}
.key-desc {
color: var(--color-text-muted);
}
/* === COMMAND LIST === */
.cmd-list {
display: flex;
flex-direction: column;
gap: 10px;
}
.cmd-item {
display: flex;
gap: 12px;
align-items: flex-start;
}
.cmd-name {
min-width: 160px;
font-size: 12px;
color: var(--color-primary);
padding-top: 1px;
}
.cmd-desc {
font-size: 12px;
color: var(--color-text-muted);
line-height: 1.5;
}
/* === PORTAL LIST === */
.portal-list {
display: flex;
flex-direction: column;
gap: 8px;
}
.portal-item {
display: flex;
align-items: center;
gap: 12px;
padding: 10px 12px;
border: 1px solid var(--color-border);
border-radius: 6px;
font-size: 12px;
transition: border-color var(--transition), background var(--transition);
}
.portal-item:hover {
border-color: rgba(74,240,192,0.35);
background: rgba(74,240,192,0.02);
}
.portal-dot {
width: 8px;
height: 8px;
border-radius: 50%;
flex-shrink: 0;
}
.dot-online { background: var(--color-primary); box-shadow: 0 0 6px var(--color-primary); }
.dot-standby { background: var(--color-warning); box-shadow: 0 0 6px var(--color-warning); }
.dot-offline { background: var(--color-text-muted); }
.portal-name {
font-weight: 600;
color: var(--color-text);
min-width: 120px;
}
.portal-desc {
color: var(--color-text-muted);
flex: 1;
}
/* === INFO BLOCK === */
.info-block {
font-size: 12px;
line-height: 1.7;
color: var(--color-text-muted);
}
.info-block p + p {
margin-top: 10px;
}
.info-block a {
color: var(--color-primary);
text-decoration: none;
}
.info-block a:hover {
text-decoration: underline;
}
.highlight {
color: var(--color-text);
font-weight: 500;
}
/* === FOOTER === */
.page-footer {
margin-top: 32px;
padding-top: 16px;
border-top: 1px solid var(--color-border);
font-size: 11px;
color: var(--color-text-muted);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: gap;
gap: 8px;
}
.footer-brand {
font-family: var(--font-display);
font-size: 10px;
letter-spacing: 0.12em;
color: var(--color-primary);
opacity: 0.7;
}
</style>
</head>
<body>
<div class="page-wrap">
<!-- Header -->
<header class="page-header">
<a href="/" class="back-link">← Back to The Nexus</a>
<h1 class="page-title">THE <span>NEXUS</span> — Help</h1>
<p class="page-subtitle">Navigation guide, controls, and system reference for Timmy's sovereign home-world.</p>
</header>
<!-- Navigation Controls -->
<section class="help-section">
<div class="section-header">
<span class="section-icon"></span>
<span class="section-title">Navigation Controls</span>
</div>
<div class="section-body">
<table class="key-table">
<tr>
<td><div class="key-group"><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd></div></td>
<td class="key-desc">Move forward / left / backward / right</td>
</tr>
<tr>
<td><div class="key-group"><kbd>Mouse</kbd></div></td>
<td class="key-desc">Look around — click the canvas to capture the pointer</td>
</tr>
<tr>
<td><div class="key-group"><kbd>V</kbd></div></td>
<td class="key-desc">Toggle navigation mode: Walk → Fly → Orbit</td>
</tr>
<tr>
<td><div class="key-group"><kbd>F</kbd></div></td>
<td class="key-desc">Enter nearby portal (when portal hint is visible)</td>
</tr>
<tr>
<td><div class="key-group"><kbd>E</kbd></div></td>
<td class="key-desc">Read nearby vision point (when vision hint is visible)</td>
</tr>
<tr>
<td><div class="key-group"><kbd>Enter</kbd></div></td>
<td class="key-desc">Focus / unfocus chat input</td>
</tr>
<tr>
<td><div class="key-group"><kbd>Esc</kbd></div></td>
<td class="key-desc">Release pointer lock / close overlays</td>
</tr>
</table>
</div>
</section>
<!-- Timmy Chat Commands -->
<section class="help-section">
<div class="section-header">
<span class="section-icon"></span>
<span class="section-title">Timmy Chat Commands</span>
</div>
<div class="section-body">
<div class="cmd-list">
<div class="cmd-item">
<span class="cmd-name">System Status</span>
<span class="cmd-desc">Quick action — asks Timmy for a live system health summary.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Agent Check</span>
<span class="cmd-desc">Quick action — lists all active agents and their current state.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Portal Atlas</span>
<span class="cmd-desc">Quick action — opens the full portal map overlay.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Help</span>
<span class="cmd-desc">Quick action — requests navigation assistance from Timmy.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Free-form text</span>
<span class="cmd-desc">Type anything in the chat bar and press Enter or → to send. Timmy processes all natural-language input.</span>
</div>
</div>
</div>
</section>
<!-- Portal Atlas -->
<section class="help-section">
<div class="section-header">
<span class="section-icon">🌐</span>
<span class="section-title">Portal Atlas</span>
</div>
<div class="section-body">
<div class="info-block">
<p>Portals are gateways to external systems and game-worlds. Walk up to a glowing portal in the Nexus and press <span class="highlight"><kbd>F</kbd></span> to activate it, or open the <span class="highlight">Portal Atlas</span> (top-right button) for a full map view.</p>
<p>Portal status indicators:</p>
</div>
<div class="portal-list" style="margin-top:14px;">
<div class="portal-item">
<span class="portal-dot dot-online"></span>
<span class="portal-name">ONLINE</span>
<span class="portal-desc">Portal is live and will redirect immediately on activation.</span>
</div>
<div class="portal-item">
<span class="portal-dot dot-standby"></span>
<span class="portal-name">STANDBY</span>
<span class="portal-desc">Portal is reachable but destination system may be idle.</span>
</div>
<div class="portal-item">
<span class="portal-dot dot-offline"></span>
<span class="portal-name">OFFLINE / UNLINKED</span>
<span class="portal-desc">Destination not yet connected. Activation shows an error card.</span>
</div>
</div>
</div>
</section>
<!-- HUD Panels -->
<section class="help-section">
<div class="section-header">
<span class="section-icon"></span>
<span class="section-title">HUD Panels</span>
</div>
<div class="section-body">
<div class="cmd-list">
<div class="cmd-item">
<span class="cmd-name">Symbolic Engine</span>
<span class="cmd-desc">Live feed from Timmy's rule-based reasoning layer.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Blackboard</span>
<span class="cmd-desc">Shared working memory used across all cognitive subsystems.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Symbolic Planner</span>
<span class="cmd-desc">Goal decomposition and task sequencing output.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Case-Based Reasoner</span>
<span class="cmd-desc">Analogical reasoning — matches current situation to past cases.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Neuro-Symbolic Bridge</span>
<span class="cmd-desc">Translation layer between neural inference and symbolic logic.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Meta-Reasoning</span>
<span class="cmd-desc">Timmy reflecting on its own thought process and confidence.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Sovereign Health</span>
<span class="cmd-desc">Core vitals: memory usage, heartbeat interval, alert flags.</span>
</div>
<div class="cmd-item">
<span class="cmd-name">Adaptive Calibrator</span>
<span class="cmd-desc">Live tuning of response thresholds and behavior weights.</span>
</div>
</div>
</div>
</section>
<!-- System Info -->
<section class="help-section">
<div class="section-header">
<span class="section-icon"></span>
<span class="section-title">System Information</span>
</div>
<div class="section-body">
<div class="info-block">
<p>The Nexus is Timmy's <span class="highlight">canonical sovereign home-world</span> — a local-first 3D space that serves as both a training ground and a live visualization surface for the Timmy AI system.</p>
<p>The WebSocket gateway (<code>server.py</code>) runs on port <span class="highlight">8765</span> and bridges Timmy's cognition layer, game-world connectors, and the browser frontend. The <span class="highlight">HERMES</span> indicator in the HUD shows live connectivity status.</p>
<p>Source code and issue tracker: <a href="https://forge.alexanderwhitestone.com/Timmy_Foundation/the-nexus" target="_blank" rel="noopener noreferrer">Timmy_Foundation/the-nexus</a></p>
</div>
</div>
</section>
<!-- Footer -->
<footer class="page-footer">
<span class="footer-brand">THE NEXUS</span>
<span>Questions? Speak to Timmy in the chat bar on the main world.</span>
</footer>
</div>
</body>
</html>

42
tests/test_help_page.py Normal file
View File

@@ -0,0 +1,42 @@
"""Tests for the /help page. Refs: #833 (Missing /help page)."""
from pathlib import Path
def test_help_html_exists() -> None:
assert Path("help.html").exists(), "help.html must exist to resolve /help 404"
def test_help_html_is_valid_html() -> None:
content = Path("help.html").read_text()
assert "<!DOCTYPE html>" in content
assert "<html" in content
assert "</html>" in content
def test_help_page_has_required_sections() -> None:
content = Path("help.html").read_text()
# Navigation controls section
assert "Navigation Controls" in content
# Chat commands section
assert "Chat" in content
# Portal reference
assert "Portal" in content
# Back link to home
assert 'href="/"' in content
def test_help_page_links_back_to_home() -> None:
content = Path("help.html").read_text()
assert 'href="/"' in content, "help page must have a link back to the main Nexus world"
def test_help_page_has_keyboard_controls() -> None:
content = Path("help.html").read_text()
# Movement keys are listed individually as <kbd> elements
for key in ["<kbd>W</kbd>", "<kbd>A</kbd>", "<kbd>S</kbd>", "<kbd>D</kbd>",
"Mouse", "Enter", "Esc"]:
assert key in content, f"help page must document the {key!r} control"