style(theme): make Jade's gold vein follow rounded corners

Jade's edge-trace hero hand-walked the panel perimeter as straight line
segments, so rounded corners chamfered into flat polygons. Retire it in
favour of the gradient-border effect, which draws via AddRect and hugs
the real corner arcs.

- theme_effects: drawGradientBorderShift gains phaseOffset + alphaMul;
  drawPanelEffects now draws it on every glass panel (position-phased so
  panels drift like veins at different depths, 0.6x alpha vs the active
  nav button), gated behind a new opt-in gradient-border-panels flag so
  button-only themes (Obsidian) are unaffected.
- jade.toml: edge-trace off; gradient-border-panels on, speed 0.10,
  jade->gold; jade motes + viewport wash/vignette kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-20 00:24:36 -05:00
parent f3776bcbe5
commit 31ebfc782e
3 changed files with 67 additions and 16 deletions

View File

@@ -115,10 +115,13 @@ surface-inline-alpha = 0.58
background-inline-alpha = 0.40
# ---------------------------------------------------------------------------
# Theme Visual Effects — Jade (polished stone sheen + gold veining)
# A soft jade specular highlight drifts across panels like light on
# polished nephrite; the active sidebar button traces a jade-to-gold
# border echoing the stone's veins — restrained, like Obsidian.
# Theme Visual Effects — Jade (veins of gold shifting through the stone)
# Jade's signature is a slow jade→gold color-shifting border on every glass
# panel + the active nav button — a vein of gold surfacing through nephrite.
# It's drawn via AddRect so it hugs the real rounded corners (no polygonal
# edge-trace). Sparse jade motes drift up the viewport. No other theme turns
# gradient-border-panels on, so the panel-wide vein is Jade's own —
# deliberately NOT Obsidian's specular glare.
# ---------------------------------------------------------------------------
[effects]
hue-cycle-enabled = { size = 0.0 }
@@ -130,25 +133,45 @@ shimmer-enabled = { size = 0.0 }
positional-hue-enabled = { size = 0.0 }
glow-pulse-enabled = { size = 0.0 }
edge-trace-enabled = { size = 0.0 }
# Specular glare — soft blurred jade highlights
specular-glare-enabled = { size = 1.0 }
# Edge-trace OFF — its hand-walked perimeter chamfers rounded corners.
# Jade's vein is the gradient-border below (corner-clean via AddRect).
edge-trace-enabled = { size = 0.0 }
edge-trace-speed = { size = 0.16 }
edge-trace-length = { size = 0.34 }
edge-trace-thickness = { size = 1.6 }
edge-trace-alpha = { size = 0.55 }
edge-trace-color = { color = "#C9A24E" }
# Specular glare OFF — that's Obsidian's signature; Jade shouldn't echo it.
specular-glare-enabled = { size = 0.0 }
specular-glare-speed = { size = 0.018 }
specular-glare-intensity = { size = 0.008 }
specular-glare-radius = { size = 0.65 }
specular-glare-count = { size = 1.0 }
specular-glare-color = { color = "rgba(150,220,180,1.0)" }
# Jade-to-gold color-shifting border on the active sidebar button
# HERO — vein of gold: a slow jade→gold color-shifting border on the active
# nav button AND (via gradient-border-panels) every glass panel. Drawn with
# AddRect so it follows the rounded corners exactly. Panels drift at a softer
# alpha and position-phased offset, so a screenful reads like veins at
# different depths rather than one synchronized pulse.
gradient-border-enabled = { size = 1.0 }
gradient-border-speed = { size = 0.12 }
gradient-border-panels = { size = 1.0 }
gradient-border-speed = { size = 0.10 }
gradient-border-thickness = { size = 1.5 }
gradient-border-alpha = { size = 0.55 }
gradient-border-color-a = { color = "#7FD1B5" }
gradient-border-color-b = { color = "#C9A24E" }
ember-rise-enabled = { size = 0.0 }
# Ambient jade motes — sparse, slow, cool green particles drifting up the
# viewport (recolored ember-rise; a different mood from dragonx's fire embers).
ember-rise-enabled = { size = 1.0 }
ember-rise-count = { size = 5.0 }
ember-rise-speed = { size = 0.18 }
ember-rise-particle-size = { size = 1.4 }
ember-rise-alpha = { size = 0.26 }
ember-rise-color = { color = "#7FD1B5" }
# Shader-like viewport overlay — deep green stone atmosphere
viewport-wash-enabled = { size = 1.0 }

View File

@@ -160,6 +160,10 @@ void ThemeEffects::loadFromTheme() {
// ---- Gradient Border Shift ----
gradient_border_.enabled = eff("gradient-border-enabled").sizeOr(0.0f) > 0.5f;
// Opt-in: also draw the shifting border on every glass panel (not just the
// active nav button). Off by default so themes that only want the button
// accent (e.g. Obsidian) are unaffected; Jade turns it on as its hero.
gradient_border_.panels = eff("gradient-border-panels").sizeOr(0.0f) > 0.5f;
gradient_border_.speed = eff("gradient-border-speed").sizeOr(0.15f);
gradient_border_.thickness = eff("gradient-border-thickness").sizeOr(1.5f);
gradient_border_.alpha = eff("gradient-border-alpha").sizeOr(0.6f);
@@ -512,11 +516,15 @@ void ThemeEffects::drawGlowPulse(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
// ============================================================================
void ThemeEffects::drawGradientBorderShift(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
float rounding) const {
float rounding, float phaseOffset,
float alphaMul) const {
if (!enabled_ || !gradient_border_.enabled) return;
// Smooth sinusoidal oscillation between color A and color B
float phase = std::sin(time_ * gradient_border_.speed * 2.0f * 3.14159265f) * 0.5f + 0.5f;
// Smooth sinusoidal oscillation between color A and color B.
// phaseOffset shifts where in the cycle this element sits so a wall of
// panels reads like veins at different depths rather than one pulse.
float phase = std::sin((time_ * gradient_border_.speed + phaseOffset)
* 2.0f * 3.14159265f) * 0.5f + 0.5f;
// Extract RGBA from both colors and lerp
RGB ca = unpackRGB(gradient_border_.colorA);
@@ -525,7 +533,7 @@ void ThemeEffects::drawGradientBorderShift(ImDrawList* dl, ImVec2 pMin, ImVec2 p
int r = ca.r + (int)((cb.r - ca.r) * phase);
int g = ca.g + (int)((cb.g - ca.g) * phase);
int b = ca.b + (int)((cb.b - ca.b) * phase);
int a = scaledAlpha(gradient_border_.alpha, bgOpacity_);
int a = scaledAlpha(gradient_border_.alpha * alphaMul, bgOpacity_);
// Draw the shifting border
dl->AddRect(pMin, pMax, IM_COL32(r, g, b, a),
@@ -896,6 +904,22 @@ void ThemeEffects::drawPanelEffects(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
float rounding) const {
if (!enabled_ || effects::isLowSpecMode()) return;
// Gradient border on panels — a slow color-shifting outline that hugs the
// panel's rounded corners (drawn via AddRect, so it follows the rounding
// exactly — no polygonal corners). Position-based phase offset makes each
// panel drift like a vein at a different depth; softer than the active
// nav button (alphaMul 0.6) so a screenful of panels stays calm.
if (gradient_border_.enabled && gradient_border_.panels) {
float w = pMax.x - pMin.x;
float h = pMax.y - pMin.y;
if (w > 80 && h > 40) { // skip small panels
float posKey = (pMin.x * 0.0073f + pMin.y * 0.0137f);
posKey = posKey - (int)posKey; // fractional 0..1
if (posKey < 0) posKey += 1.0f;
drawGradientBorderShift(dl, pMin, pMax, rounding, posKey, 0.6f);
}
}
// Edge trace on panels — use position-based phase offset so each
// panel's tracer is at a different position around the border
if (edge_trace_.enabled) {

View File

@@ -69,9 +69,12 @@ public:
void drawEdgeTrace(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
float rounding) const;
/// Draw a border that shifts between two colors over time (gem-like)
/// Draw a border that shifts between two colors over time (gem-like).
/// phaseOffset (0..1) shifts this element's point in the color cycle so
/// many panels don't pulse in unison; alphaMul scales the whole effect.
void drawGradientBorderShift(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
float rounding) const;
float rounding, float phaseOffset = 0.0f,
float alphaMul = 1.0f) const;
/// Draw ember particles that rise from an element (fire theme)
void drawEmberRise(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax) const;
@@ -186,6 +189,7 @@ private:
struct GradientBorderConfig {
bool enabled = false;
bool panels = false; ///< also draw on glass panels, not just the active nav button
float speed = 0.15f; ///< full color shift cycles per second
float thickness = 1.5f; ///< border line thickness in pixels
float alpha = 0.6f; ///< peak alpha