Private
Public Access
0
0
Files
manual_slop/docs/guide_nerv_theme.md
T

14 KiB
Raw Blame History

NERV Theme (Tactical Console Aesthetic)

Top | Shaders & Window | Architecture


Overview

The NERV Theme is a selectable high-density visual variant inspired by the NERV tactical consoles from the Neon Genesis Evangelion anime. It uses sharp geometry, a near-black palette, CRT-style scanlines, status flickering, and alert animations to produce a "tactical command center" aesthetic that emphasizes information density and operational urgency.

This guide covers:

  1. Design Philosophy — Why NERV looks the way it does
  2. Visual Components — Palette, geometry, typography, effects
  3. Implementation — The theme_nerv.py and theme_nerv_fx.py modules
  4. Configurationconfig.toml keys
  5. Performance — Cost of FX rendering
  6. Testing — Visual verification

Design Philosophy

The NERV theme is built around three principles:

  1. Black Void Background — The dominant color is near-black (0,0,0 to 8,8,8 range). This reduces visual noise and lets accent colors pop.
  2. Zero-Rounding Geometry — No rounded corners on panels, buttons, frames, or separators. Sharp rectangles convey "instrumentation," not "consumer app."
  3. Operational Urgency — Status indicators flicker (subtle, low frequency). Errors trigger red border pulses. This is intentional: it makes operational state changes immediately visible to the operator.

The theme is opt-in, not the default. Most users will use the standard dark or light themes. NERV is for users who want maximum information density and a "tactical" feel.


Visual Components

Color Palette

The palette constants in src/theme_nerv.py:8-13 (computed from RGB triples via _c()):

Constant RGB (0-255) Hex Usage
BLACK (0, 0, 0) #000000 Primary window, panel, popup, frame, title, menu, scrollbar, button, tab backgrounds
STEEL (224, 224, 216) #E0E0D8 Text, separator, scrollbar-grab-hovered, resize-grip-hovered
NERV_ORANGE (255, 152, 48) #FF9830 Border, scrollbar-grab, resize-grip, nav-cursor, border-shadow alpha=0
ALERT_RED (255, 72, 64) #FF4840 Used as 1.0,0.0,0.0 with sin-pulsed alpha in AlertPulsing.render (not as a steady color in NERV_PALETTE)
DATA_GREEN (80, 255, 80) #50FF50 Check-mark, slider-grab-active, plot-histogram, drag-drop-target, nav-windowing-highlight
WIRE_CYAN (32, 240, 255) #20F0FF Scrollbar-grab-active, slider-grab, plot-lines, separator-hovered, resize-grip-active

The full NERV_PALETTE dict (47 imgui.Col_ entries, src/theme_nerv.py:15-63) maps each constant to the relevant imgui style color. The "header/header-hovered/header-active" colors are semi-transparent NERV orange (alphas 60, 100, 140) used for table-header and tree-node selection.

Geometry

  • Window corners: Square (0px rounding)
  • Panel corners: Square
  • Button corners: Square
  • Frame rounding: Disabled (ImGuiStyle.FrameRounding = 0)
  • Window rounding: Disabled (ImGuiStyle.WindowRounding = 0)
  • Child rounding: Disabled

This produces a "military hardware" feel that contrasts with consumer-app aesthetics.

Typography

  • Primary font: Inter (already used by other themes)
  • Monospace font: Maple Mono (for code, telemetry, logs)
  • Font sizes: Slightly smaller than the default theme to maximize information density
  • Font weights: Medium for body, Bold for headers

Status Flickering

The StatusFlicker.get_alpha() method in src/theme_nerv_fx.py:67-73 returns a value in the range [0.7, 1.0] from a sine wave:

return 0.85 + 0.15 * math.sin(time.time() * 20.0)

The angular frequency is hard-coded (20.0 rad/s ≈ 3.18 Hz, not 0.5 Hz) and the method is currently a utility — there is no production caller wiring it into a tier indicator at the time of writing.

CRT Scanlines

CRTFilter.render(width, height) in src/theme_nerv_fx.py:8-65 is invoked once per frame from theme_2.render_post_fx() (at src/theme_2.py:400-408) when NERV is active. The render method:

  1. Draws 1.2px (major, every 4 lines) and 0.8px (minor, every 2 lines) horizontal black lines at alphas 0.08 / 0.04
  2. Draws 1.0px vertical black lines every 3px at alpha 0.05 (simulated aperture-grille shadow mask)
  3. Draws 20 nested rounded-rectangle outlines with exponentially increasing alpha (max 0.25) for vignette/tube-curvature
  4. Adds 40 small white noise pixels per frame with flickering alpha (0.01-0.04) modulated by a 60 Hz sin wave

The scanline alphas and noise density are hard-coded in the FX source — there is no config knob for them.

Performance cost: ~1-2ms per frame on a 1920×1080 display with default settings (per the original 2026-05 design estimate; the new shader-less draw-list implementation in src/theme_nerv_fx.py may be faster).

Alert Animations

AlertPulsing in src/theme_nerv_fx.py:75-97 is a stateful on/off border overlay:

  1. update(status: str) at :79-83 sets self.active = status.lower().startswith("error") — i.e. any AI status string that begins with "error" (case-insensitive) triggers the pulse. There is no MMA-specific state-machine check; the call site at src/theme_2.py:405 passes the live ai_status from the controller.
  2. render(width, height) at :85-97 is a no-op while not self.active. When active, it draws a full-screen red rectangle with alpha pulsing at 0.05 + 0.15 * (sin(t·4) + 1) / 2 (so alpha oscillates 0.05 ↔ 0.20 at ~0.64 Hz, no decay).
  3. The pulse persists for the entire duration that ai_status starts with "error"; it does not have a 1.5-second auto-decay. There is no alert_pulse_duration_seconds config.

The color is the constant (1.0, 0.0, 0.0) in src/theme_nerv_fx.py:96 (pure red, not the ALERT_RED constant), and the thickness is 10px.


Implementation

src/theme_nerv.py — Base Theme (88 lines)

Defines the 6 color constants (lines 8-13), the NERV_PALETTE dict (lines 15-63, 47 imgui.Col_ entries), and the apply_nerv() function (lines 65-87). The actual apply_nerv() is a tight loop over the palette dict, not a hand-written sequence of style.colors[col] = ... assignments:

def apply_nerv() -> None:
    style = imgui.get_style()
    for col_enum, rgba in NERV_PALETTE.items():
        style.set_color_(col_enum, imgui.ImVec4(*rgba))

    # Hard Edges
    style.window_rounding    = 0.0
    style.child_rounding     = 0.0
    style.frame_rounding     = 0.0
    style.popup_rounding     = 0.0
    style.scrollbar_rounding = 0.0
    style.grab_rounding      = 0.0
    style.tab_rounding       = 0.0

    # Border sizes
    style.window_border_size = 1.0
    style.frame_border_size  = 1.0
    style.popup_border_size  = 1.0
    style.child_border_size  = 1.0
    style.tab_border_size    = 1.0

src/theme_nerv_fx.py — Visual Effects (97 lines)

Three classes, no module-level entry point:

  • CRTFilter (lines 8-65) — __init__(self) sets self.enabled = True; render(self, width, height) is the scanline/vignette/noise overlay. The enabled flag is the only runtime toggle; the GUI controls it via the crt_enabled parameter to theme_2.render_post_fx().
  • StatusFlicker (lines 67-73) — get_alpha(self) returns a hard-coded 3.18 Hz sine. Currently a utility; no production caller (see §"Status Flickering" above).
  • AlertPulsing (lines 75-97) — __init__(self) sets self.active = False; update(self, status) enables the pulse if status.lower().startswith("error"); render(self, width, height) is the no-op-or-pulse draw.

There is no render_nerv_fx(fx_state: dict) aggregator. The actual entry point that wires the FX layer into the GUI is theme_2.render_post_fx(width, height, ai_status, crt_enabled) at src/theme_2.py:400-408:

def render_post_fx(width: float, height: float, ai_status: str, crt_enabled: bool) -> None:
    """Updates and renders the alert and CRT filters."""
    theme_nerv_fx = _require_warmed("src.theme_nerv_fx")
    alert_pulsing = theme_nerv_fx.AlertPulsing()
    crt_filter    = theme_nerv_fx.CRTFilter()
    alert_pulsing.update(ai_status)
    alert_pulsing.render(width, height)
    crt_filter.enabled = crt_enabled
    crt_filter.render(width, height)

Note: theme_2.py:111 has a code comment saying "NERV FX objects (CRTFilter, AlertPulsing, StatusFlicker) are now created [in render_post_fx]" — this confirms the per-frame create-and-discard pattern. The previous design (FX as long-lived module-level singletons) is no longer in use.

Activation

The NERV theme is activated via the GUI's theme picker (NERV is one of the 4 built-in syntax palettes selectable via the multi-theme TOML system). The apply_nerv() call is wired into the theme-switch path of theme_2.py. To switch programmatically:

from src.theme_nerv import apply_nerv
apply_nerv()

The FX layer's CRTFilter.enabled is set per-frame by the caller of theme_2.render_post_fx(crt_enabled=...) — there is no [nerv].fx_enabled config key (see §"Configuration" below for why).


Configuration

There is no [nerv] config section in config.toml. As of 2026-06-10, the NERV FX layer's parameters (scanline alpha, flicker frequency, alert pulse color, alert pulse duration) are all hard-coded in src/theme_nerv_fx.py and have no TOML or env-var override. The only runtime toggles are:

  • CRTFilter.enabled — set per-frame by the caller of theme_2.render_post_fx(crt_enabled=...); the GUI uses the NERV theme's "FX enabled" toggle to drive this.
  • AlertPulsing.active — set automatically by update(ai_status) to True if ai_status.lower().startswith("error").

Earlier versions of this guide (pre-2026-06-10) documented a [nerv] section with fx_enabled, scanline_alpha, flicker_rate_hz, alert_pulse_duration_seconds, and alert_pulse_color keys. None of those keys were ever wired into the source code — they were aspirational documentation, not configuration. This is the "stale doc" that the docs-sync track on 2026-06-10 surfaced and removed.


Performance

Effect Cost (1920×1080) Cost (4K) Notes
Scanlines (FBO) 1-2ms/frame 4-8ms/frame Scales with resolution.
Status flicker <0.1ms/frame <0.1ms/frame Per-element alpha calc, trivial.
Alert pulse <0.1ms/frame <0.1ms/frame Per-frame interpolation, trivial.

Total NERV overhead: ~1-2ms/frame on a 1920×1080 display with default settings. For a 60 FPS target (16.67ms/frame), this leaves 14+ ms for the rest of the GUI.

Lower-end GPU: Reduce scanline_alpha (cheaper blending) or disable FX entirely (fx_enabled = false). The base NERV theme (colors, geometry, fonts) has no measurable GPU cost.

Latency impact: None. The FX layer is purely visual; it doesn't block the main render thread.


Interaction with Other Subsystems

MMA Dashboard

The NERV theme enhances the MMA Dashboard with:

  • Color-coded tier indicators (using the NERV accent colors)
  • Status flickering on the active tier
  • Red border pulse on "blocked" / "error" states

Diagnostics Panel

The FPS / CPU / Input Lag display uses the NERV palette. Performance warnings (FPS < 30, CPU > 80%) flash in NERV red.

Approval Modal

When the Execution Clutch suspends on a destructive action, the approval modal uses the NERV orange for the "Approve" button and the standard gray for "Reject". This makes the destructive action visually distinct.


Testing

Unit Tests

  • tests/test_theme_nerv.pyapply_nerv() correctly sets all colors, geometry, and fonts.
  • tests/test_theme_nerv_fx.py — FX rendering functions don't raise, produce expected output dimensions.
  • tests/test_theme_nerv_alert.py — Alert pulse animation runs for the configured duration and decays correctly.

Visual Verification

The NERV theme is primarily a visual feature; functional tests are limited. The [nerv] config keys are read at theme application time; a misconfigured key defaults gracefully.

For visual verification in live_gui tests:

def test_nerv_theme_active(live_gui):
    # Activate NERV theme
    client.activate_theme("nerv")
    
    # Verify the active theme
    status = client.get_ui_performance()  # Or a theme-specific endpoint
    assert "theme" in status
    assert status["theme"] == "nerv"

The visual appearance (colors, scanlines) is best verified manually by a human reviewer.


Limitations

  1. Scanlines Are Static: The current implementation uses a fixed scanline pattern. Animated scanlines (slow vertical scroll) are not implemented.

  2. No Color Customization in GUI: The NERV palette is hardcoded. To customize colors, edit src/theme_nerv.py directly (no GUI editor for NERV-specific colors).

  3. No Theme Mixing: The NERV theme is a single selectable theme. It cannot be mixed with other themes (e.g., "NERV colors but default rounding").

  4. Performance Cost on Low-End GPUs: The FBO scanline pass may be too expensive on integrated graphics or older GPUs. The fx_enabled flag is the workaround.

  5. Accessibility: The black void palette with high-contrast accents is not WCAG AA compliant for text contrast in all combinations. The active state color (NERV orange) on black meets AA, but secondary text (gray on black) is borderline. Users with low vision may need a different theme.


Future Work

  • CRT Curvature: A more advanced shader could apply screen-space curvature to mimic CRT monitors. Currently planned but not implemented.
  • Bloom Effect: For high-saturation accent colors, a subtle bloom could make the NERV orange "glow." Adds GPU cost.
  • Animated Scanlines: Slow vertical scroll of the scanline pattern for a more "active" CRT feel.
  • Custom Palette Editor: Allow the user to override individual NERV colors via the GUI.
  • Hybrid Themes: Allow partial NERV adoption (e.g., NERV colors but default rounding).

See guide_shaders_and_window.md for the underlying shader and window frame infrastructure.