Luna UI's Effects system adds composable, shader-based visual effects to any UI Toolkit VisualElement. Six effects — Glow, Outline, Shadow, Gradient, Pattern, and Shine — run through a single Shader Graph uber shader, are toggled independently via shader keywords, and compose additively as an overlay.

Effects Overview

EffectDescription
GlowSoft colored light emanating from element edges inward
OutlineColored border band with configurable softness
ShadowInner shadow / edge darkening for depth
GradientTwo-color gradient overlay at any angle
PatternTiled texture overlay with blend modes
ShineAnimated diagonal light sweep

Quick Start

Attach a UIEffectManipulator to any VisualElement with a fluent API:

csharp
using CupkekGames.Luna.Effects; var myButton = root.Q<Button>("my-button"); myButton.AddManipulator(new UIEffectManipulator() .WithGlow(color: Color.cyan, intensity: 1.5f, size: 10f));

Stack multiple effects with method chaining:

csharp
myButton.AddManipulator(new UIEffectManipulator() .WithGradient(colorA: Color.blue, colorB: Color.purple) .WithGlow(color: new Color(0.5f, 0.3f, 1f, 0.8f), intensity: 1.2f) .WithShine(speed: 0.8f));

Animated effects (Shine) start automatically when using WithShine().

Direct API

For more control, create a UIEffectElement and manage effects manually:

csharp
var overlay = new UIEffectElement(); myElement.Add(overlay); var glow = overlay.AddEffect<GlowEffect>(); glow.Color = Color.cyan; glow.Intensity = 2f; glow.Size = 12f; overlay.RefreshEffects();

Inspector API (No Code)

  1. Add Component > UIEffectController to any GameObject with a UIDocument
  2. Set Target Element Name to the element's name attribute
  3. Configure effects in the Inspector — changes apply at runtime automatically

Built-in Effects

Glow

Soft colored light emanating from element edges inward.

ParameterTypeDefaultRangeDescription
ColorColorWhite (0.8a)Glow color and base opacity
Intensityfloat1.00–3Brightness multiplier
Sizefloat8.00–30+How far glow extends inward (px)
csharp
element.AddManipulator(new UIEffectManipulator() .WithGlow(color: new Color(0f, 1f, 0.8f, 0.9f), intensity: 2f, size: 15f));

Tips: High Intensity (2–3) with saturated colors creates a neon look. Size is relative to element dimensions — larger elements need larger values.

Outline

A colored border band at element edges.

ParameterTypeDefaultRangeDescription
ColorColorWhiteOutline color
Widthfloat2.00–10Border thickness (px)
Softnessfloat1.00–5Edge blur amount
csharp
element.AddManipulator(new UIEffectManipulator() .WithOutline(color: Color.red, width: 3f, softness: 0.5f));

Tips: Low Softness (0–0.5) gives a crisp border. High Softness (2–5) gives a feathered edge.

Shadow

Inner shadow that darkens element edges, providing depth.

ParameterTypeDefaultRangeDescription
ColorColorBlack (0.5a)Shadow color
OffsetVector2(4, 4)Directional bias
Blurfloat4.00–20How far shadow extends inward
Intensityfloat1.00–1Shadow opacity multiplier
csharp
element.AddManipulator(new UIEffectManipulator() .WithShadow(color: new Color(0f, 0f, 0f, 0.7f), offset: new Vector2(4, 4), blur: 6f));

Tips: This is an inner shadow rendered as an overlay. Offset controls which edges appear darker, creating a light-direction effect.

Gradient

Two-color gradient overlay at any angle.

ParameterTypeDefaultRangeDescription
ColorAColorWhiteStart color
ColorBColorBlackEnd color
Anglefloat0.00–360Rotation in degrees (0 = top-to-bottom)
Intensityfloat1.00–1Opacity multiplier
csharp
element.AddManipulator(new UIEffectManipulator() .WithGradient( colorA: new Color(1f, 0.2f, 0.5f), colorB: new Color(0.2f, 0.5f, 1f), angle: 45f));

Tips: Use semi-transparent colors to tint the underlying element rather than fully cover it.

Pattern

Tiled texture overlay with configurable blend mode.

ParameterTypeDefaultDescription
TextureTexture2DnullThe pattern texture
TintColorWhiteColor multiplied with texture
ScaleVector2(1, 1)Tiling scale
OffsetVector2(0, 0)UV offset
Intensityfloat1.0Opacity multiplier (0–1)
BlendModePatternBlendModeMultiplyMultiply, Additive, or Overlay
csharp
element.AddManipulator(new UIEffectManipulator() .WithPattern(myTexture, tint: Color.white, scale: new Vector2(2, 2)));

Tips: Ensure your texture has Wrap Mode set to Repeat for tiling. Scale values >1 produce more repetitions (smaller pattern).

Shine

Animated diagonal light sweep across the element.

ParameterTypeDefaultRangeDescription
ColorColorWhite (0.5a)Shine band color
Widthfloat0.10.01–0.5Band width (fraction of element)
Anglefloat45.00–360Sweep angle in degrees
Speedfloat1.00–5Animation speed
Intensityfloat1.00–2Brightness multiplier
csharp
element.AddManipulator(new UIEffectManipulator() .WithShine(color: new Color(1f, 1f, 1f, 0.4f), width: 0.12f, speed: 0.8f));

Tips: Lower Speed (0.3–0.6) looks elegant. Narrow Width (0.01–0.05) gives a laser-like sweep, wider (0.2–0.5) gives a soft wash. Requires animation — the Manipulator handles this automatically via WithShine(). If using the direct API, call overlay.StartAnimation().

Combining Effects

Effects are additive overlays — each enabled effect outputs an RGBA color contribution and all contributions are summed in the shader. Effects are independent; enabling Glow does not affect how Gradient renders.

CombinationUse CaseExample
Glow + OutlineNeon button highlightWithGlow(...).WithOutline(...)
Gradient + ShinePolished premium panelWithGradient(...).WithShine(...)
Gradient + GlowColorful emphasisWithGradient(...).WithGlow(...)
Outline + ShadowDepth and definitionWithOutline(...).WithShadow(...)
Glow + Gradient + ShineMaximum impactUse sparingly

Combined Presets

csharp
// Neon — vibrant edge glow new UIEffectManipulator() .WithGlow(color: new Color(0f, 1f, 0.8f, 0.95f), intensity: 2.5f, size: 16f) .WithOutline(color: new Color(0.2f, 1f, 0.85f), width: 2f, softness: 0.5f); // Glass — translucent with light sweep new UIEffectManipulator() .WithGradient(colorA: new Color(1f, 1f, 1f, 0.35f), colorB: new Color(0.85f, 0.85f, 1f, 0.15f)) .WithShine(color: new Color(1f, 1f, 1f, 0.5f), width: 0.15f, speed: 0.6f, angle: 30f); // Fire — warm glow with gradient new UIEffectManipulator() .WithGlow(color: new Color(1f, 0.4f, 0f, 0.95f), intensity: 2.5f, size: 14f) .WithGradient(colorA: new Color(1f, 0.85f, 0f), colorB: new Color(1f, 0.15f, 0f)); // Frost — cool tones with subtle shine new UIEffectManipulator() .WithGlow(color: new Color(0.6f, 0.85f, 1f, 0.8f), intensity: 1.8f, size: 12f) .WithGradient(colorA: new Color(0.92f, 0.96f, 1f), colorB: new Color(0.35f, 0.55f, 0.85f)) .WithShine(color: new Color(1f, 1f, 1f, 0.4f), width: 0.08f, speed: 0.4f);

Real-World Examples

Inventory Rarity Slots

csharp
// Common — subtle outline AttachEffect("slot-common", new UIEffectManipulator() .WithOutline(color: new Color(0.7f, 0.7f, 0.7f), width: 1.5f, softness: 0.5f)); // Rare — blue glow AttachEffect("slot-rare", new UIEffectManipulator() .WithOutline(color: new Color(0.4f, 0.6f, 1f), width: 2f, softness: 0.5f) .WithGlow(color: new Color(0.4f, 0.6f, 1f, 0.5f), intensity: 1f, size: 8f)); // Epic — purple glow AttachEffect("slot-epic", new UIEffectManipulator() .WithOutline(color: new Color(0.8f, 0.4f, 1f), width: 2f, softness: 0.5f) .WithGlow(color: new Color(0.8f, 0.4f, 1f, 0.7f), intensity: 1.5f, size: 10f)); // Legendary — gold glow + shine AttachEffect("slot-legendary", new UIEffectManipulator() .WithOutline(color: new Color(1f, 0.8f, 0.3f), width: 2.5f, softness: 0.5f) .WithGlow(color: new Color(1f, 0.8f, 0.3f, 0.9f), intensity: 2f, size: 12f) .WithShine(color: new Color(1f, 0.95f, 0.6f, 0.4f), width: 0.1f, speed: 0.5f));

Notification Card

csharp
AttachEffect("notification", new UIEffectManipulator() .WithGlow(color: new Color(1f, 0.85f, 0.3f, 0.8f), intensity: 1.5f, size: 12f) .WithShine(color: new Color(1f, 0.95f, 0.7f, 0.5f), width: 0.15f, speed: 0.6f));

Game Menu Buttons

csharp
// Primary action — gradient + glow AttachEffect("menu-play", new UIEffectManipulator() .WithGradient(colorA: new Color(0.3f, 0.7f, 1f, 0.7f), colorB: new Color(0.15f, 0.4f, 0.9f, 0.4f)) .WithGlow(color: new Color(0.4f, 0.7f, 1f, 0.6f), intensity: 1f, size: 8f)); // Secondary action — subtle outline AttachEffect("menu-settings", new UIEffectManipulator() .WithOutline(color: new Color(0.6f, 0.6f, 0.7f, 0.5f), width: 1f, softness: 1f));

Architecture

How It Works

VisualElement (your button, panel, etc.) └── UIEffectElement (absolute overlay, same size as parent) ├── Creates a RenderTexture matching element size ├── Creates a Material from the LunaUIEffect Shader Graph ├── Enables/disables shader keywords per effect ├── Sets material properties (colors, floats, textures) ├── Renders the shader to the RT via GL.DrawMeshNow └── Displays the RT via style.backgroundImage

Shader Graph — Uber Shader

The LunaUIEffect.shadergraph is an Unlit transparent shader with 6 Boolean Keywords — one per effect. Each effect is a Sub Graph:

Sub GraphKeywordShader Properties
LunaEffectGlow_EFFECT_GLOW_GlowColor, _GlowIntensity, _GlowSize
LunaEffectOutline_EFFECT_OUTLINE_OutlineColor, _OutlineWidth, _OutlineSoftness
LunaEffectShadow_EFFECT_SHADOW_ShadowColor, _ShadowOffset, _ShadowSize, _ShadowIntensity
LunaEffectGradient_EFFECT_GRADIENT_GradientColorA, _GradientColorB, _GradientAngle, _GradientIntensity, _GradientType, _GradientReverse, _GradientColorBias
LunaEffectPattern_EFFECT_PATTERN_PatternTex, _PatternTint, _PatternScale, _PatternOffset, _PatternIntensity
LunaEffectShine_EFFECT_SHINE_ShineColor, _ShineWidth, _ShineAngle, _ShineSpeed, _ShineIntensity, _ShineCycleTime

All sub graphs share a common _ElementSize property. Each sub graph:

  1. Takes UV + ElementSize + effect parameters as inputs
  2. Outputs an RGBA color contribution
  3. Is gated by a Keyword node (On = pass through, Off = zero)

All 6 outputs are summed via Add nodes into the fragment output. When a keyword is disabled, the shader compiler strips that variant entirely — zero runtime cost for disabled effects.

Glow Sub Graph Detail

The LunaEffectGlow sub graph creates an edge-detection glow using a rounded-rectangle SDF approach:

  • Inputs: UV, ElementSize, per-edge widths/strengths, corner radius, softness, angle, offsets
  • Process: Computes distance from element edges per-side, applies configurable strength and softness per edge, combines with corner radius smoothing
  • Has a _MODE keyword for switching between glow calculation modes
  • Output: RGBA color contribution blended with the glow color and intensity

C# Bridge

UIEffect (abstract) — defines: ShaderKeyword, Order, ApplyToMaterial() ├── GlowEffect — keyword: _EFFECT_GLOW (Order: 50) ├── OutlineEffect — keyword: _EFFECT_OUTLINE (Order: ?) ├── ShadowEffect — keyword: _EFFECT_SHADOW (Order: ?) ├── GradientEffect — keyword: _EFFECT_GRADIENT (Order: ?) ├── PatternEffect — keyword: _EFFECT_PATTERN (Order: ?) └── ShineEffect — keyword: _EFFECT_SHINE (Order: ?)
  • UIEffectStack manages the ordered list of effects and handles keyword/property application
  • UIEffectMaterialPool resolves the shader via UIEffectSettings ScriptableObject or Shader.Find fallback

Sample Demo

The Components > Effects sample includes an interactive demo showcasing all effects.

Import: Window > Package Manager > Luna UI > Samples > Components

Files:

  • UIEffectDemo.uxml — Full demo layout
  • UIEffectDemo.uss — Demo styling
  • UIEffectDemoController.cs — All effect examples in code

Demo Sections

SectionWhat It Shows
Individual EffectsEach of the 6 effects on separate buttons
Real-World UsageNotification cards, inventory rarity slots (Common → Legendary), game menu buttons, status panels
Combined PresetsNeon, Glass, Fire, and Frost preset combinations
Interactive PlaygroundLive controls — toggle effects on/off, adjust sliders for each parameter, pick colors from a palette
Stress TestSpawns 20 animated elements with rainbow hues to benchmark performance

Playground Controls

The right panel targets a playground element with live controls:

  • Per-effect toggles — Enable/disable Glow, Outline, Shadow, Gradient, Shine
  • Parameter sliders — Adjust intensity, size, width, softness, angle, speed per effect
  • Color pickers — Preset color buttons (Cyan, Red, Gold, Green, Purple, White, Black)
  • Preset buttons — One-click Neon, Glass, Fire, Ice, and Clear

Running the Demo

  1. Import the Components sample from the Luna UI package
  2. Open the UIEffectDemo scene (or add the UIEffectDemoController to a scene with a UIDocument)
  3. Assign a UIDocument and optionally a pattern Texture2D on the controller
  4. Enter Play mode

Setup

UIEffectSettings (Required)

The system needs the LunaUIEffect shader at runtime:

  1. Right-click in Project > Create > Luna > UI Effect Settings
  2. Name it UIEffectSettings
  3. Place it in any Resources folder (e.g., Assets/Resources/UIEffectSettings.asset)
  4. Drag the LunaUIEffect Shader Graph into the Uber Shader field

Without this, the system falls back to Shader.Find("Shader Graphs/LunaUIEffect"), which requires the shader to be referenced by a material in the build.

Performance

  • Each effected element creates one RenderTexture and one Material
  • Static effects (no Shine) only re-render when the element resizes or effects change
  • Animated effects (Shine) re-render every frame (configurable interval)
  • Guideline: 10–20 effected elements is fine. 50+ animated elements will impact frame rate
  • Elements with zero effects have zero cost
  • Use the demo stress test to benchmark your target hardware

Troubleshooting

ProblemSolution
Effect not visibleCheck Console for shader-not-found errors. Verify element has non-zero size. Ensure Shader Graph compiles.
Properties not updatingCall overlay.RefreshEffects() after changing parameters via the direct API.
Wrong colors / washed outEffects are additive — multiple bright effects will over-saturate. Reduce Intensity or use semi-transparent colors.
Shader outputs nothingVerify keyword reference names match C# (e.g., _EFFECT_GLOW with leading underscore). Check the Add chain connects to both Base Color and Alpha.
Shine not animatingCall overlay.StartAnimation() when using the direct API. The Manipulator handles this for WithShine().
Effects clipped at edgesExpected — the overlay renders within element bounds. Use transparent padding for effects that extend beyond.

Adding a Custom Effect

  1. C# class — Extend UIEffect, define ShaderKeyword, Order, and ApplyToMaterial()
  2. Sub Graph — Create in Runtime/Shaders/SubGraphs/Effects/, with UV + ElementSize + parameters as inputs, RGBA output
  3. Uber Graph — Add a Boolean Keyword + properties, wire the sub graph through a Keyword node into the Add chain
  4. Manipulator (optional) — Add a With___() method to UIEffectManipulator
  5. Inspector (optional) — Add fields to UIEffectData and update ApplyTo()

See the existing documentation for a detailed step-by-step example using a hypothetical PulseEffect.

API Reference

UIEffectManipulator

MethodParametersReturns
WithGlow()color, intensity, sizeself
WithOutline()color, width, softnessself
WithShadow()color, offset, blur, intensityself
WithGradient()colorA, colorB, angle, intensityself
WithPattern()texture, tint, scale, intensity, blendModeself
WithShine()color, width, angle, speed, intensityself
WithAnimation()intervalMsself
OverlayUIEffectElement (available after attach)

UIEffectElement

MethodDescription
AddEffect<T>()Add effect by type (creates new instance)
RemoveEffect<T>()Remove effect by type
GetEffect<T>()Get existing effect (or null)
HasEffect<T>()Check if effect exists
RefreshEffects()Re-render after parameter changes
StartAnimation(intervalMs)Begin animation loop
StopAnimation()Stop animation loop

UIEffectController (MonoBehaviour)

FieldDescription
UIDocumentSource UIDocument
Target Element NameName attribute of target element
Effect DataSerialized effect configuration
ApplyEffects()Re-apply from serialized data at runtime

Settings

Theme

Light

Contrast

Material

Dark

Dim

Material Dark

System

Sidebar(Light & Contrast only)

Light
Dark

Font Family

DM Sans

Wix

Inclusive Sans

AR One Sans

Direction

LTR
RTL