Initial release: RadiantWave v1.0
This commit is contained in:
@@ -0,0 +1,201 @@
|
||||
# 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
|
||||
Reference in New Issue
Block a user