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".
- 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/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.
- 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()`.
-`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.
-`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.
- 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.