# 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. ### Plugin System - `autoload/plugin_manager.gd` — autoload singleton, scans `res://plugins/*/plugin.cfg` at startup. - Each plugin folder contains a `plugin.cfg` INI file with `[plugin]` metadata and `[tile_N]` entries defining tiles (id, name, scene path, min/max grid spans). - Tile IDs are scoped as `{plugin_id}/{tile_id}` to guarantee global uniqueness. - `PluginManager.instantiate_tile(tile_id)` loads the tile scene, instantiates it, and tags the root node with `tile_id` and `tile_config` metadata. - `scripts/plugin_tile.gd` — class_name `PluginTile`, extends `ModuleBase`. Plugin tiles extend this instead of ModuleBase directly. Stores `tile_id` and `tile_config` properties, also written to node metadata for grid/layout access. ### Layout System - `autoload/layout_manager.gd` — autoload singleton for saving/restoring tile grid positions. - Layout files stored as INI in `res://config/layouts/{name}.cfg`. Each entry maps a `tile_id` to `{col, row, w, h}`. - `save_layout()` writes the current in-memory layout to disk. `load_layout(name)` reads it back. - `switch_layout(name)` saves current layout, loads the named one, emits signals. - Current layout name persisted in `ConfigManager` as `layout_current`. - Layout auto-saves on every `module_placed` and `module_resized` signal from `DashboardGrid`. ### Config System ### 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 │ ├── plugin_manager.gd # Plugin scanning, tile instantiation │ └── layout_manager.gd # Layout save/load/switch ├── config/ # Configuration files (INI format) │ ├── default.cfg # Shipped defaults, tracked in git │ ├── config.cfg # User overrides, gitignored (auto-generated) │ └── layouts/ # Saved layout files (*.cfg) ├── plugins/ # Plugin folders │ └── system_monitor/ # Built-in system monitoring plugin │ ├── plugin.cfg │ └── tiles/ │ ├── cpu/ │ ├── memory/ │ └── 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 │ ├── plugin_tile.gd # Base class for plugin tiles (extends ModuleBase) │ └── 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 (0–0.5) where 0.05 ≈ 12px on a 240px‑tall cell. ### Git Workflow - Main branch: `main` - Feature branches: `feature/` - 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.