# GUI The RocketSmith GUI is an offline-first web dashboard that displays project data in real time as the agent works. It runs as a single `index.html` file that can be opened via `file://` (no server needed) or served by the built-in GUI server for live updates. The `gui` subagent (`agents/gui.md`) manages the GUI lifecycle — starting/stopping the server and navigating to pages. Domain agents (openrocket, cadsmith, etc.) generate the data; the gui agent ensures it's visible. ## Architecture ``` index.html (project root) ↓ loads gui/main.js (React bundle) gui/data.js (offline data snapshot) ↓ connects to WebSocket server (live file-change events) ``` - **Offline mode:** `data.js` contains a snapshot of all project files. The page works without a server. - **Live mode:** The WebSocket server watches the project directory and pushes file-change events. The frontend patches `window.__OFFLINE_DATA__` in memory so all reads stay current. - **Dev mode:** Vite HMR for frontend development. Proxies `/ws` and `/api` to the Python backend. **The frontend never fetches files directly.** All data reads go through `window.__OFFLINE_DATA__` — a JavaScript object containing the full project state. Text files are stored as strings (JSON parsed inline), binary files (STL) as `{"__b64__": ""}` objects converted to blob URLs on demand. Routes like `/parts/nose_cone` are just React Router keys — the component looks up `gui/parts/nose_cone.json` in the in-memory bundle. ## MCP Tools | Tool | Description | |------|-------------| | `gui_server` | Start, stop, or dev-launch the GUI server. | | `gui_navigate` | Navigate the GUI to a specific route path via WebSocket command. | ### gui_server **Actions:** | Action | What it does | |--------|-------------| | `start` | Copies built GUI files to the project, writes `data.js` snapshot, starts the Python backend, opens `index.html` in the browser. Called automatically by `rocketsmith_setup` — use directly to recover if the GUI didn't open. | | `dev` | Starts Vite HMR + Python WebSocket server. If a production server is already running, piggybacks on it (no duplicate WS server). | | `stop` | Kills all GUI server processes for the project (reads PID files). | **Parameters:** - `action` (required): `"start"`, `"dev"`, or `"stop"` - `project_dir`: Path to the project directory - `pid`: (stop only) Kill a specific PID instead of reading the PID file - `host`: Bind address (default `127.0.0.1`) - `port`: (start only) Backend port (default `24880`) **Dev mode ports:** - Vite: `5173` - WebSocket (standalone): `24881` - Production backend: `24880` Dev mode detects a running production server on `24880` and proxies to it instead of starting a second WebSocket server. ### gui_navigate Sends a navigation command over WebSocket to all connected GUI clients. **Parameters:** - `path` (required): Route path to navigate to ## Pages & Routes The GUI uses a `HashRouter`. URLs look like `http://127.0.0.1:5173/#/parts/nose_cone`. | Route | Page | Description | |-------|------|-------------| | `#/` | Agent Feed | Live dashboard with draggable cards. Shows part cards, component tree, flight simulation, build progress, and session log. **Navigate here when switching to a new task.** | | `#/flights` | Flight Viewer | Flight simulation charts rendered from `openrocket/flights/*.json` timeseries data. | | `#/component-tree` | Component Tree | Rocket profile visualization, CG/CP/stability badges, and hierarchical component list with DFAM fate annotations. | | `#/assembly` | Assembly Viewer | 3D spatial layout of assembled parts from `gui/assembly.json`. | | `#/parts/` | Part Detail | Tabbed view with 3D model viewer and build123d source code for a specific part. | **Part routes use `#/parts/`** — no `.json` extension, no `gui/` prefix. Routes are just keys for React Router — the frontend never fetches files directly. All data is read from the in-memory `window.__OFFLINE_DATA__` bundle, where the part is stored under the key `gui/parts/.json`. ### Navigation Pattern Navigate to a detail page (e.g. `#/flights`) to **present finished results**. When the pipeline moves on to the next piece of work, navigate back to `#/` so the user sees new cards appear in the Agent Feed. The feed auto-focuses on the most recently updated card. ``` gui_navigate(path="#/flights") # present flight results # ... cadsmith starts generating parts ... gui_navigate(path="#/") # return to feed for new activity ``` ## Agent Feed The default page (`/`) is the Agent Feed — a grid-based dashboard where cards appear as the agent works. ### Cards | Card | Content | Default Size | |------|---------|-------------| | Part Card (one per part) | Tabbed: 3D model viewer + source code | 3 cols × 4 rows | | Component Tree | Rocket profile SVG (with hover highlighting), CG/CP/stability, component list | 3 cols × 3 rows | | Flight Simulation | Summary badges (apogee, Vmax, stability), tabbed charts (altitude, velocity, stability, thrust) with burnout/apogee markers | 3 cols × 3 rows | | Build Progress | Per-part preview generation status with progress bars | 2 cols × 1 row | | Session Log | Timestamped log of agent actions | 2 cols × 1 row | ### Grid System - Fixed cell size: `280px` wide × `180px` tall, `16px` gap - Grid expands to fill the viewport; scrolls if cards extend beyond - Cards are placed at explicit grid positions (col, row) with explicit spans - Drag-and-drop to reposition cards - Resize handles on right and bottom edges - Layout persisted to `localStorage` under `rocketsmith:preferences` - "Reset Layout" button clears stored positions and auto-places cards - "Auto-focus" toggle scrolls to the active (most recently updated) card - Active card highlighted with orange border ### Data Flow 1. WebSocket server sends snapshot events on connect (replays current project state) 2. Live file-change events update the in-memory data bundle 3. Cards read from `window.__OFFLINE_DATA__` via `fetchJson()`/`fetchText()`/`fileUrl()` 4. Binary files (STL) are base64-encoded and converted to blob URLs for Three.js ## File Layout All GUI-related files live under `gui/` in the project directory: ``` gui/ ├── main.js ← React bundle (from Vite build) ├── data.js ← Offline data snapshot (generated by server) ├── .gui.pid ← Production server PID ├── .gui-dev.pid ← Dev server PIDs ├── files-tree.json ← Directory tree snapshot ├── component_tree.json ← Component hierarchy with DFAM annotations ├── assembly.json ← Spatial layout for 3D viewer ├── parts/ ← Per-part JSON metadata ├── logs/session.jsonl ← Agentic session log ├── progress/ ← Per-part preview generation progress └── assets/ ├── stl/ ← STL meshes (generated by preview tool) ├── png/ ← PNG thumbnails ├── gif/ ← Rotating GIF animations └── txt/ ← ASCII animation frames ``` ## Offline Data Bundle `data.js` sets `window.__OFFLINE_DATA__` with: ```js window.__OFFLINE_DATA__ = { filesTree: [...], // Recursive directory tree projectInfo: { name, path }, files: { "gui/component_tree.json": { ... }, // Parsed JSON "gui/logs/session.jsonl": "...", // Raw text "gui/assets/stl/nose_cone.stl": { "__b64__": "..." }, // Base64 binary } }; ``` - Text files stored as strings (JSON parsed inline) - Binary files (STL) stored as `{"__b64__": ""}` → converted to blob URLs by `fileUrl()` - Generated on server start and shutdown; live events keep the in-memory copy current