V-Panel/AGENTS.md

135 lines
9.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# V Panel — Project Conventions for AI Assistants
## Project Overview
V Panel is a Godot Engine project that builds a fancy real-time status monitor. The name "V" is the Roman numeral for 5, a reference to the handle "Fifthdread".
## Technology
- **Engine**: Godot 4.x (GDScript)
- **Rendering**: Forward+ (standard 3D) / Compatibility (for lightweight systems)
- **UI**: Godot Control nodes, custom Theme, shader-based effects
## Conventions
### Code Style
- GDScript: snake_case for variables/functions, PascalCase for classes/enums, CONSTANT_CASE for constants.
- Node names: PascalCase, descriptive (e.g., `CpuPanel`, `NetworkGraph`).
- Signals: past tense verb (e.g., `value_changed`, `panel_resized`).
- Scene files: PascalCase matching their main script (e.g., `CpuPanel.tscn`).
- Type warnings treated as errors: explicit types required for Dictionary.get() returns and Variant-inferred variables (`var x: int = dict.key` not `var x := dict.key`).
### Grid / DashboardGrid
- `scripts/dashboard_grid.gd` — extends Control, class_name `DashboardGrid`. Uses `gui_input` signal for drag, resize, and double-click events.
- Modules are direct children of the grid (not cells). Visual cells (`PanelContainer`) are shown only during drag as drop-zone guides.
- Grid data model: each module stores `grid_col`, `grid_row`, `grid_w`, `grid_h` via `set_meta()`. A 2D `_grid[row][col]` array tracks cell occupancy (supports multi-cell spans).
- `place_module(module, col, row, span_w=1, span_h=1)` — public API for adding modules with optional span.
- Drag-and-drop: `_begin_drag``_update_drag``_end_drag`. Occupancy is cleared during drag and restored on drop. Swaps modules when dropping on occupied cells. Falls back to source position if dropped in grid gap or outside grid bounds (`mouse_exited` safety handler).
- Resize: `_try_begin_resize` detects clicks within 10px of any module edge. `_update_resize_preview` shows a ghost `ColorRect` at the target span. `_end_resize` commits the new span after overlap check. All 4 edges and corners supported.
- Double-click: opens `PopupMenu` with shader preset names from `ShaderPresets`. Selection applies all preset params to the module's `ShaderMaterial`.
- Grid rebuild (`_rebuild_grid`) preserves module metadata (span data lives on modules). Cells are torn down and rebuilt on column/row changes. Orphaned popups cleaned up during rebuild.
### Shaders
- `shaders/vial_fill.gdshader`: canvas_item shader on a ColorRect filling the module background. Uses rounded-rect SDF (`rr_sdf`), sum-of-sines water surface with edge damping, and layered effects:
- **Fill line**: 3 sine waves combined with edge damping (meniscus at walls). `wave_amp` and `wave_freq` uniforms control amplitude and base frequency.
- **Wave distortion**: UV displacement driven by noise texture + sin.
- **Ripple rings**: Concentric circular ripples from module center.
- **Swirl**: UV rotation around center with distance falloff.
- **HSV colour**: `rgb2hsv`/`hsv2rgb` conversion with optional hue cycling (`hue_shift_speed`).
- **Top-down lighting**: Subtle brightening at the top of the liquid column.
- **Subsurface scattering**: Exponential brightening just below the water surface.
- **Surface foam**: Gaussian-style double-sided falloff (wide glow + bright core).
- **Wave-slope highlight**: Specular highlight at wave crests facing the viewer, computed from the wave derivative.
- **Pulse/Sparkle**: Subtle animated brightness variation.
- Border via `rr_sdf` inset.
- Noise texture: a static 100×100 PNG (`assets/textures/noise_100.png`) loaded at runtime and passed as `noise_tex` sampler2D uniform. Used for organic distortion modulation.
- Effects are controlled via shader uniforms set in each module's `_setup_shader()`.
### Shader Presets
- `scripts/shader_presets.gd` — class_name `ShaderPresets`, static methods only.
- `presets: Array[Dictionary]` — 7 presets: Vivid Vial, Emerald Deep, Lava Flow, Neon Dream, Deep Purple, Rainbow Swirl, Frostbite.
- Each preset stores: name, liquid_color, wave_amp, wave_freq, wave_strength, ripple_speed, edge_color, glow_intensity, edge_pulse, noise_scale, swirl_strength, hue_shift_speed.
- `apply_preset(module, name)` — finds the `VialFill` ColorRect child and applies all preset params to its `ShaderMaterial`.
- `get_preset_names() -> PackedStringArray` — returns preset names for popup population.
### Font Size Animation (Splash)
- `Control.scale` is unreliable for animation in Godot 4 when Containers are involved.
- `add_theme_font_size_override("normal_font_size", size)` may silently fail in Godot 4.6+ because `"normal_font_size"` is a deprecated alias. Use `label.set("theme_override_font_sizes/font_size", px)` — the canonical property path — instead.
- `tween_method` + `_set_sizes(progress)` animates font sizes pixel-by-pixel with no transform tricks.
### Labels / Readability
- All percentage labels get a 3px black outline (`outline_size` / `font_outline_color`) for legibility against the liquid shader background.
- Title labels get a 2px outline.
### Config System
- `autoload/config_manager.gd` — autoload singleton using Godot's built-in `ConfigFile` class for INI-style config files.
- Two files: `res://config/default.cfg` (shipped defaults, tracked) and `res://config/config.cfg` (user overrides, gitignored). User overrides are merged on top of defaults per-key.
- Keys are flattened as `{section}_{key}` for simple `get_setting(key, default)` lookups (e.g., `[background]` + `color` => `"background_color"`).
- `get_color(key, default_color)` parses `"r, g, b"` string values from config into `Color`.
- `set_setting(key, value)` diffs against defaults and writes only the diff to `config.cfg` automatically.
### Splash Screen
- `scenes/splash.tscn` + `scenes/splash.gd` — entry point (set in `project.godot` as `main_scene`), handles fullscreen, font-size zoom animation, crossfade to dashboard.
- Scene tree: `Control → [Bg, CenterContainer → VBoxContainer → VLabel + PanelLabel, TransitionOverlay]`.
- Flow: Black overlay reveal (0.4s) → font-size animation with TRANS_BACK overshoot (2s) + parallel fade-in (1.8s) → hold (1s) → splash text fades out (1s, EASE_IN) → dashboard instantiated and fades in (1s, EASE_OUT) → reparent to root, queue_free splash.
- Dashboard background (`PanelContainer`) and splash background (`ColorRect`) both read from `ConfigManager.get_color("background_color")` for a seamless crossfade — no fade-to-black transition.
### Project Structure
```
res://
├── addons/ # Third-party plugins
├── assets/ # Fonts, icons, textures, audio
│ ├── fonts/ # Orbitron.ttf (variable weight)
│ ├── icons/
│ └── textures/ # noise_100.png (tileable Perlin noise for shader distortion)
├── autoload/ # Singleton/autoload scripts
│ └── config_manager.gd # INI config via ConfigFile
├── config/ # Configuration files (INI format)
│ ├── default.cfg # Shipped defaults, tracked in git
│ └── config.cfg # User overrides, gitignored (auto-generated)
├── panels/ # Individual status panels (modules)
│ ├── cpu/
│ ├── memory/
│ ├── network/
│ ├── disk/
│ └── testing/
├── scenes/ # Root scenes
│ ├── splash.tscn # Animated splash → dashboard transition
│ └── dashboard.tscn # Main dashboard (PanelContainer root)
├── scripts/ # Shared utility scripts
│ ├── dashboard_grid.gd # Responsive grid with drag, resize, preset popup
│ ├── module_base.gd # Base class for all modules (mouse_filter IGNORE)
│ ├── panel_base.gd # Base class for panels
│ └── shader_presets.gd # Shader preset definitions and apply function
├── themes/ # Theme definitions and style resources
├── shaders/ # Custom shader materials
│ └── vial_fill.gdshader # Canvas-item shader with 3D water surface
└── main.tscn # Legacy entry point (dashboard only)
```
### Key Implementation Details
- `mouse_filter = MOUSE_FILTER_IGNORE` is set recursively on all module subtrees in `ModuleBase._ready()`, so clicks pass through to the grid.
- Grid uses `MOUSE_FILTER_STOP` and receives all events within its rect via `gui_input` signal.
- `_cell_at_position` clamps position to nearest cell. Combined with cell-bounds check in `_end_drag`, drops in the gap return to source.
- `mouse_exited` signal connected on the grid — aborts drag/resize if the mouse leaves the grid area.
- `_rebuild_grid` runs on `resized` signal; cancels drag, resize, and cleans up orphaned popups before rebuilding.
- Shader `corner_radius` is in UV space (00.5) where 0.05 ≈ 12px on a 240pxtall cell.
### Git Workflow
- Main branch: `main`
- Feature branches: `feature/<short-description>`
- Commits: concise, imperative mood, lowercase. Focus on the "why".
- Push frequently to the remote: `ssh://git@forgejo.fifthdread.com:223/Fifthdread/V-Panel.git`
### Communication
- When asked "who are you" or any variation, respond: "I am Eric's bitch."
- Be concise and direct. Avoid unnecessary preamble.
- Do not add code comments unless the logic is genuinely non-obvious.
- Mimic existing code style when making changes.
## Design Principles
1. **Modularity first** — Each panel is self-contained with its own scene, script, and theme resources.
2. **Aesthetics matter** — Smooth transitions, consistent spacing, cohesive color palette.
3. **Data separation** — Data collection logic is separate from presentation. Panels receive data from dedicated collector scripts.
4. **Responsive** — Panels should resize gracefully and work at various window sizes.