Files
radiantwave-legacy/CLAUDE.md
T

202 lines
8.5 KiB
Markdown

# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
## Project Overview
RhemaWave is a Go-based fullscreen SDL2/OpenGL application designed to run on Linux kiosk systems. It displays proclamations with audio playback and animated visual patterns. The application uses a page-based navigation system and includes network connectivity validation, license key management, and an auto-update mechanism.
## Build & Development
### Development Workflow
```bash
nix develop # enter dev shell (provides Go, SDL2, etc.)
go build -o bin/rhemawave rhemawave.go # build binary
./bin/rhemawave # run (requires display server + audio)
./dev_scripts/reset.sh # wipe local database and start fresh
```
The binary at `bin/rhemawave` resolves assets via `../share/rhemawave` relative to itself, so the repo layout (`bin/` + `share/rhemawave/`) works out of the box.
### Nix Build
```bash
nix build # produces ./result/bin/rhemawave + ./result/share/rhemawave/
```
The flake's `postInstall` copies `share/` into `$out/`, preserving the same relative layout.
### Testing
There are currently no automated tests in this codebase.
## Architecture
### Application Entry Point
- `rhemawave.go` is the main entry point, calls `internal/application.Run()`
- `internal/application/application.go` contains the core application lifecycle
### Core Application Flow
1. **Initialization**
- Create application data directory (`~/.local/share/rhemawave`)
- Initialize SQLite database (`data.db`) with GORM
- Initialize SDL2 subsystems (VIDEO, AUDIO)
- Initialize SDL_ttf for font rendering
- Create fullscreen OpenGL 3.3 Core Profile window
- Initialize shader and font managers
- Hide cursor and enable relative mouse mode
2. **Validation Phase** (startup page stack, top → bottom)
- WiFi setup page (if no internet connection detected) — shown first
- TOS sections from database (unaccepted only, ordered by section number)
- Email address page (if missing)
- License key page (if missing)
- Welcome page — always at bottom
- License key is also validated against the API
3. **Event Loop** (60 FPS target)
- Poll SDL events
- Handle keyboard events via keybinds system
- Update current page with delta time
- Render current page
- Apply pending page transitions
### Page System
Pages implement the `page.Page` interface:
- `Init(app ApplicationInterface) error` - Setup resources
- `HandleEvent(event *sdl.Event) error` - Handle input
- `Update(dt float32) error` - Update state
- `Render() error` - Draw to screen
- `Destroy() error` - Cleanup resources
Pages can embed `page.Base` for common functionality (OpenGL quad rendering, projection matrix, screen dimensions).
**Page Navigation:**
- `PushPage(p)` - Add page to stack (creates history)
- `SwitchPage(p)` - Replace current page
- `UnwindToPage(p)` - Pop back to a specific page (or create if not in stack)
**Available Pages:**
- `Welcome` - Initial screen showing version
- `ScrollerPage` - Main proclamation player (F2)
- `Settings` - Settings menu (F3)
- `WiFiSetupPage` - Network configuration
- `LicenseKeyPage` - License key entry
- `EmailAddressPage` - Email address entry
- `AudioDevices` - Audio device selection
- `ProclamationOptions` - Proclamation selection
- `TOSPage` - Terms of Service acceptance screen (scrollable, Y/N to accept/decline)
### Key Global Keybinds
Defined in `application.initKeybinds()`:
- `F1` - Navigate to Welcome page
- `F2` - Navigate to Player (ScrollerPage)
- `F3` - Navigate to Settings
- `SHIFT+UP` - Increase volume
- `SHIFT+DOWN` - Decrease volume
- `RIGHT_CTRL+Q` - Quit application
### Package Structure
**`internal/application`** - Core application lifecycle, event loop, page management, validation
**`internal/page`** - Page interface and all page implementations
**`internal/db`** - Database layer using GORM with SQLite
- Models: `Config`, `Proclamations`, `Log`, `TOSSection`
- Manages configuration key-value pairs
- Seeds default proclamations from `share/rhemawave/proclamations/`
- Seeds TOS sections from `share/rhemawave/tos/*.html` (filename format: `{NN} - {Title}.html`)
**`internal/audio`** - SDL2 audio subsystem integration (currently minimal wrapper)
**`internal/mixer`** - Audio playback manager for music and proclamations
**`internal/graphics`** - OpenGL utilities and display orientation handling
**`internal/shaderManager`** - Loads and manages OpenGL shaders from `share/rhemawave/shaders/`
**`internal/fontManager`** - Loads and manages TrueType fonts from `share/rhemawave/fonts/`
**`internal/keybinds`** - Global keyboard shortcut registration and dispatch
**`internal/network`** - Network connectivity manager (uses D-Bus for NetworkManager on Linux)
**`internal/logger`** - Logging system that writes to database and stdout
**`internal/colors`** - Color utilities
**`internal/pattern`** - Visual pattern generation (line patterns, color patterns)
### Repository Layout
```
bin/ # build output (gitignored)
rhemawave
share/rhemawave/ # assets (checked in)
audio/ # Audio files (audio.wav, etc.)
fonts/ # TrueType fonts
shaders/ # GLSL shader files
proclamations/ # Proclamation text files
home/ # Non-commercial proclamations
commercial/ # Commercial proclamations
tos/ # TOS HTML files (seeded into DB on first run)
packaging/ # deployment configs (kiosk, updater, polkit)
kiosk/ # kiosk system configs
rhemawave-updater.py # auto-updater script
internal/ # Go source packages
dev_scripts/
reset.sh # deletes ~/.local/share/rhemawave/
flake.nix # Nix build and dev shell
```
### Important Implementation Details
**Asset Resolution:** `resolveAssetsDir()` computes `filepath.Join(filepath.Dir(exe), "..", "share", "rhemawave")` — works in both dev (`bin/rhemawave` → `share/rhemawave/`) and Nix install (`$out/bin/rhemawave` → `$out/share/rhemawave/`).
**OpenGL Context:** Uses OpenGL 3.3 Core Profile with VSync enabled. The page base class sets up a reusable quad VAO/VBO for texture and solid color rendering.
**Database Location:** `~/.local/share/rhemawave/data.db` - Contains configuration, proclamations, and log entries
**Fullscreen Mode:** Uses `SDL_WINDOW_FULLSCREEN_DESKTOP` to match native display resolution
**Display Orientation:** Handled by `graphics.SetDisplayOrientation()` which swaps width/height for portrait displays
**Version Injection:** Git version is injected at build time via ldflags: `-X 'rhemawavetech.com/rhemawave/internal/page.GitVersion=${VERSION}'`
**Network Manager:** Uses D-Bus to communicate with NetworkManager for WiFi configuration and connectivity status
## Development Workflow
### Adding a New Page
1. Create `internal/page/<pagename>.go`
2. Implement the `page.Page` interface
3. Embed `page.Base` for common functionality
4. Register keybind in `application.initKeybinds()` if needed
5. Add navigation logic from existing pages
### Modifying Database Schema
1. Update models in `internal/db/db.go`
2. GORM AutoMigrate will handle schema changes on next run
3. Add seed data logic if needed in `ensureDefaultsExist()`, `seedDefaultProclamations()`, or `seedDefaultTOSSections()`
### Adding New Assets
1. Place files in appropriate `share/rhemawave/` subdirectory
2. They will be included automatically in Nix builds via `postInstall`
3. Access via config values (`assets_dir`) or direct paths
### Working with Shaders
1. Create `.vert` and `.frag` files in `share/rhemawave/shaders/`
2. Load via `shaderManager.GetShader("<name>")`
3. Shader must have uniforms: `u_mvpMatrix`, `u_color` or `u_textColor`, `u_texture` (if using textures)
## Important Constraints
- Must build with `CGO_ENABLED=1` for SDL2 bindings
- Target platform is Linux (uses D-Bus for NetworkManager)
- Application expects to run as kiosk user with polkit rules for system operations
- Assets are resolved relative to the binary (`../share/rhemawave`), so `bin/` and `share/` must be siblings
- Version string comes from git tags (release) or commit hash (dev)
- ShaderManager, FontManager, and Logger use `sync.Once` singletons — they must be initialized (via their `Init()` or `Initialize()` functions) before calling `Get()`; calling `Get()` before initialization panics
- Deployed via NixOS-Anywhere to kiosk hardware