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.
| Effect | Description |
|---|---|
| Glow | Soft colored light emanating from element edges inward |
| Outline | Colored border band with configurable softness |
| Shadow | Inner shadow / edge darkening for depth |
| Gradient | Two-color gradient overlay at any angle |
| Pattern | Tiled texture overlay with blend modes |
| Shine | Animated diagonal light sweep |
Attach a UIEffectManipulator to any VisualElement with a fluent API:
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:
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().
For more control, create a UIEffectElement and manage effects manually:
var overlay = new UIEffectElement();
myElement.Add(overlay);
var glow = overlay.AddEffect<GlowEffect>();
glow.Color = Color.cyan;
glow.Intensity = 2f;
glow.Size = 12f;
overlay.RefreshEffects();UIEffectController to any GameObject with a UIDocumentname attributeSoft colored light emanating from element edges inward.
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
Color | Color | White (0.8a) | — | Glow color and base opacity |
Intensity | float | 1.0 | 0–3 | Brightness multiplier |
Size | float | 8.0 | 0–30+ | How far glow extends inward (px) |
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.
A colored border band at element edges.
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
Color | Color | White | — | Outline color |
Width | float | 2.0 | 0–10 | Border thickness (px) |
Softness | float | 1.0 | 0–5 | Edge blur amount |
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.
Inner shadow that darkens element edges, providing depth.
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
Color | Color | Black (0.5a) | — | Shadow color |
Offset | Vector2 | (4, 4) | — | Directional bias |
Blur | float | 4.0 | 0–20 | How far shadow extends inward |
Intensity | float | 1.0 | 0–1 | Shadow opacity multiplier |
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.
Two-color gradient overlay at any angle.
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
ColorA | Color | White | — | Start color |
ColorB | Color | Black | — | End color |
Angle | float | 0.0 | 0–360 | Rotation in degrees (0 = top-to-bottom) |
Intensity | float | 1.0 | 0–1 | Opacity multiplier |
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.
Tiled texture overlay with configurable blend mode.
| Parameter | Type | Default | Description |
|---|---|---|---|
Texture | Texture2D | null | The pattern texture |
Tint | Color | White | Color multiplied with texture |
Scale | Vector2 | (1, 1) | Tiling scale |
Offset | Vector2 | (0, 0) | UV offset |
Intensity | float | 1.0 | Opacity multiplier (0–1) |
BlendMode | PatternBlendMode | Multiply | Multiply, Additive, or Overlay |
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).
Animated diagonal light sweep across the element.
| Parameter | Type | Default | Range | Description |
|---|---|---|---|---|
Color | Color | White (0.5a) | — | Shine band color |
Width | float | 0.1 | 0.01–0.5 | Band width (fraction of element) |
Angle | float | 45.0 | 0–360 | Sweep angle in degrees |
Speed | float | 1.0 | 0–5 | Animation speed |
Intensity | float | 1.0 | 0–2 | Brightness multiplier |
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().
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.
| Combination | Use Case | Example |
|---|---|---|
| Glow + Outline | Neon button highlight | WithGlow(...).WithOutline(...) |
| Gradient + Shine | Polished premium panel | WithGradient(...).WithShine(...) |
| Gradient + Glow | Colorful emphasis | WithGradient(...).WithGlow(...) |
| Outline + Shadow | Depth and definition | WithOutline(...).WithShadow(...) |
| Glow + Gradient + Shine | Maximum impact | Use sparingly |
// 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);// 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));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));// 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));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.backgroundImageThe LunaUIEffect.shadergraph is an Unlit transparent shader with 6 Boolean Keywords — one per effect. Each effect is a Sub Graph:
| Sub Graph | Keyword | Shader 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:
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.
The LunaEffectGlow sub graph creates an edge-detection glow using a rounded-rectangle SDF approach:
_MODE keyword for switching between glow calculation modesUIEffect (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 applicationUIEffectMaterialPool resolves the shader via UIEffectSettings ScriptableObject or Shader.Find fallbackThe Components > Effects sample includes an interactive demo showcasing all effects.
Import: Window > Package Manager > Luna UI > Samples > Components
Files:
UIEffectDemo.uxml — Full demo layoutUIEffectDemo.uss — Demo stylingUIEffectDemoController.cs — All effect examples in code| Section | What It Shows |
|---|---|
| Individual Effects | Each of the 6 effects on separate buttons |
| Real-World Usage | Notification cards, inventory rarity slots (Common → Legendary), game menu buttons, status panels |
| Combined Presets | Neon, Glass, Fire, and Frost preset combinations |
| Interactive Playground | Live controls — toggle effects on/off, adjust sliders for each parameter, pick colors from a palette |
| Stress Test | Spawns 20 animated elements with rainbow hues to benchmark performance |
The right panel targets a playground element with live controls:
UIEffectDemoController to a scene with a UIDocument)UIDocument and optionally a pattern Texture2D on the controllerThe system needs the LunaUIEffect shader at runtime:
UIEffectSettingsResources folder (e.g., Assets/Resources/UIEffectSettings.asset)LunaUIEffect Shader Graph into the Uber Shader fieldWithout this, the system falls back to Shader.Find("Shader Graphs/LunaUIEffect"), which requires the shader to be referenced by a material in the build.
| Problem | Solution |
|---|---|
| Effect not visible | Check Console for shader-not-found errors. Verify element has non-zero size. Ensure Shader Graph compiles. |
| Properties not updating | Call overlay.RefreshEffects() after changing parameters via the direct API. |
| Wrong colors / washed out | Effects are additive — multiple bright effects will over-saturate. Reduce Intensity or use semi-transparent colors. |
| Shader outputs nothing | Verify 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 animating | Call overlay.StartAnimation() when using the direct API. The Manipulator handles this for WithShine(). |
| Effects clipped at edges | Expected — the overlay renders within element bounds. Use transparent padding for effects that extend beyond. |
UIEffect, define ShaderKeyword, Order, and ApplyToMaterial()Runtime/Shaders/SubGraphs/Effects/, with UV + ElementSize + parameters as inputs, RGBA outputWith___() method to UIEffectManipulatorUIEffectData and update ApplyTo()See the existing documentation for a detailed step-by-step example using a hypothetical PulseEffect.
| Method | Parameters | Returns |
|---|---|---|
WithGlow() | color, intensity, size | self |
WithOutline() | color, width, softness | self |
WithShadow() | color, offset, blur, intensity | self |
WithGradient() | colorA, colorB, angle, intensity | self |
WithPattern() | texture, tint, scale, intensity, blendMode | self |
WithShine() | color, width, angle, speed, intensity | self |
WithAnimation() | intervalMs | self |
Overlay | — | UIEffectElement (available after attach) |
| Method | Description |
|---|---|
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 |
| Field | Description |
|---|---|
UIDocument | Source UIDocument |
Target Element Name | Name attribute of target element |
Effect Data | Serialized effect configuration |
ApplyEffects() | Re-apply from serialized data at runtime |
Settings
Theme
Light
Contrast
Material
Dark
Dim
Material Dark
System
Sidebar(Light & Contrast only)
Font Family
DM Sans
Wix
Inclusive Sans
AR One Sans
Direction