Shader-backed immediate rendering for modern Garry's Mod interfaces.
Smooth analytical shapes · rich gradients · procedural materials · text effects
antialiased coverage clipping · shared backdrop blur · Plain GLua + Lux
MGFX helps build polished HUDs, scoreboards, shops, inventories, status panels, radial menus, and other game interfaces without turning every visual effect into a pile of temporary geometry and Lua-side bookkeeping.
MGFX is a renderer, not a UI framework. It owns drawing, effects, clipping, and shader/fallback routing. Your code still owns layout, input, focus, animation state, hit testing, component lifecycle, and panel behavior.
Read the docs · Plain GLua quick start · Lux quick start · API reference
MGFX scales from a compact radial selector to full-screen settings and dense live scoreboard surfaces while keeping the same immediate drawing model.
Radial controls · Settings surface · Live scoreboard
A modern Source UI often needs more than a flat draw.RoundedBox: gradients,
soft shadows, worn materials, masked images, glowing headings, non-rectangular
clipping, and blurred surfaces all have different rendering and state needs.
MGFX gives those operations one consistent immediate API.
| Common hand-built approach | MGFX approach |
|---|---|
| High-segment Lua polygons for smooth shapes | Analytical/SDF shape coverage on focused shader paths |
| Stacked boxes or generated textures for gradients | Multi-stop shader gradients with curves, high-precision LUTs, and dithering |
| Repeating a complete shape for each shadow layer | Explicit layered shadows; the source body is drawn once |
| Capturing and blurring the framebuffer per glass panel | Shared backdrop capture and separable blur per frame/level |
| Binary stencil edges for a mixed-content shape clip | Continuous coverage composite with real antialiased edges |
| Geometry recipes for stripes, smoke, and wear | Procedural pattern paint clipped inside the existing shape pass |
| One expensive text route for every label | Native text by default; composed shader text only when effects need it |
This is not a promise that every effect costs one draw. Blur, framebuffer transactions, shadows, and glows still have real GPU costs. MGFX makes those costs explicit, reusable where possible, and diagnosable at runtime.
Simple drawing stays simple and immediate:
MGFX.RoundedBox(40, 40, 320, 72, 10, Color(18, 25, 34, 235))No style table, command object, intermediate target, or general end-of-frame scheduler is created for that call.
Use an Ex style when the design needs named effects:
local cardStyle = MGFX.CompileStyle({
radius = 14,
fill = MGFX.LinearGradientStops(0, 0, 1, 1, {
{0.00, Color(25, 36, 47, 238)},
{0.55, Color(15, 25, 34, 232)},
{1.00, Color(8, 15, 22, 238)},
}, "smoothstep"),
stroke = {
color = Color(130, 255, 174, 72),
width = 2,
kind = "dash",
length = 12,
gap = 6,
},
shadow = {
x = 0,
y = 8,
blur = 22,
spread = 2,
color = Color(0, 0, 0, 135),
},
backdrop = {
blur = 10,
level = 0,
tint = Color(7, 15, 22, 110),
},
pattern = MGFX.WornPattern({
color = Color(0, 0, 0, 34),
edgeColor = Color(150, 255, 180, 45),
grain = 0.55,
fractal = 0.34,
scratches = 0.18,
edge = 0.38,
seed = "scoreboard-card",
}),
})
MGFX.RoundedBoxEx(40, 40, 420, 180, cardStyle)| Directory | Use it when | Public API |
|---|---|---|
lua-mgfx/ |
Your addon or gamemode uses ordinary GLua | local table from include("mgfx/init.lua") |
lux-mgfx/ |
Your project is compiled with Lux | mgfx.api.* |
docs/ |
You need shared behavior and API documentation | applies to both runtimes |
The implementations share the same renderer model and are maintained in
behavioral sync. Plain GLua is not generated from Lux; lua-mgfx/ is the
canonical ordinary-addon implementation.
-- Plain GLua
local mgfx = include("mgfx/init.lua")
mgfx.RoundedBoxEx(x, y, w, h, style)// Lux
import * as mgfx from "@lux/mgfx"
mgfx.api.roundedBoxEx(x, y, w, h, style)
MGFX is substantially more than a rounded-box replacement.
- Rounded rectangles with scalar or independent corner radii
- Chamfered rectangles with independent corner cuts
- Circles, capsules, convex polygons, and regular polygons
- Diamonds, directional carets, lines, and capless lines
- Progress bars and segmented bars
- Rings, arcs, and straight-edged sectors
- Centered
solid,dot,dash, anddot-dashstrokes
Patterned strokes use an isolated shader pass and retain a CPU fallback. Closed-shape periods are fitted to the perimeter so the returning pattern does not visibly disagree with its mathematical start phase.
MGFX.RoundedBoxEx(x, y, w, h, {
radius = 12,
fill = Color(18, 24, 32),
stroke = {
color = Color(90, 190, 255),
width = 3,
kind = "dot-dash",
length = 12,
gap = 6,
offset = 0,
},
})The legacy stroke = Color(...) plus strokeWidth form remains supported.
- Solid colors
- Two-color and multi-stop linear gradients
- Circular and elliptical radial gradients
- Conic gradients
- Shape-, ring-, and sector-local radial/angular gradients
- Shader-native gradient curves:
linear,smoothstep,smootherstep,ease-in,ease-out,ease-in-out,exponential,gaussian, andinverse-square
Curves remap the existing shader coordinate before LUT sampling; they do not add a draw pass. Multi-stop gradients use a packed 16-bit RGBA LUT and stable screen-space dithering to reduce visible low-alpha banding.
local topLight = MGFX.EllipticalRadialGradient(0.5, -0.15, 0.72, 1.35, {
{0.00, Color(132, 255, 148, 224)},
{1.00, Color(18, 48, 30, 0)},
}, nil, "exponential")Centers may sit outside the primitive, which makes top-origin spotlights and wide non-circular light fields possible without a separate shader or pass.
Patterns are shader paint slots clipped to their shape—not recipes that emit dozens of extra boxes, lines, or polygons.
StripePatternSmokePatternWornPattern- Image and material paint sources
local worn = MGFX.WornPattern({
color = Color(0, 0, 0, 44),
edgeColor = Color(218, 208, 184, 78),
fractal = 0.44,
grain = 0.64,
scratches = 0.30,
edge = 0.54,
scale = 32,
grainScale = 5.6,
scratchScale = 26,
scratchWidth = 0.045,
edgeWidth = 7,
angle = -14,
warp = 0.035,
seed = "inventory-card",
})WornPattern is tuned for subdued roughness, sparse scuffs, short directional
scratches, and broken edge wear—not as a generic smoke overlay.
| Effect | What it means |
|---|---|
shadow |
A projected soft pass derived from the full solid shape mask; supports offset, blur, spread, softness, opacity, and multiple layers. |
outerGlow |
Exterior-only edge light; offset biases the glow without turning it into a projected shadow. |
innerGlow |
Edge light clipped inside the source shape. |
backdrop |
Samples and tints the framebuffer inside the current shape or image mask; it is not a shadow. |
Compatible shadow + outerGlow work is fused for rounded boxes, chamfers,
rings, and image masks while their style fields and visual semantics remain
separate.
Layered shadows avoid redrawing the entire source shape for each layer:
shadow = {
{x = 0, y = 1, blur = 2, color = Color(0, 0, 0, 90)},
{x = 0, y = 8, blur = 24, color = Color(0, 0, 0, 80)},
}Backdrop blur is shared by engine frame and integer backdrop.level. The first
blurred backdrop at a level captures the framebuffer and runs the horizontal
and vertical axes; matching later shapes reuse that prepared result. Use
recapture = true only when a later draw must deliberately include newer
framebuffer content at the same level.
- Materials, textures, render targets, texture names, and icons
contain,cover,fill, andstretchfit modes- UV and crop control
- Rounded, chamfer, circle, capsule, and texture masks
- Image-local shadow, glow, backdrop, stroke, and transforms
- Allocation-light positional
ImageUV(...)
An image style mask belongs to one image draw. Reusable mixed-content clipping uses the separate coverage Mask API below.
Plain labels, player names, table rows, and changing counters stay on the native GMod text path by default. The composer route is used only when a style needs gradient fill, stroke, glow, shadow, weight, italic, or tracking.
MGFX.TextEx("OVERTIME", "DermaLarge", x, y, nil,
TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER, {
fill = MGFX.LinearGradient(0, 0, 1, 0,
Color(255, 210, 90), Color(255, 80, 70)),
glow = {color = Color(255, 96, 78, 120), blur = 10},
shadow = {x = 0, y = 2, blur = 4, color = Color(0, 0, 0, 150)},
})Useful APIs include Text, TextEx, TextBoxEx, MeasureText,
MeasureTextBox, and PrewarmText. Prewarm predictable display strings, not
ordinary native labels.
MGFX deliberately separates two concepts:
ImageEx(..., {mask = ...})masks one image draw.MGFX.Mask(painter)defines reusable coverage forMGFX.Clip(...), which can clip any mixture of MGFX shapes, images, text, and native drawing.
local badgeMask = MGFX.Mask(function(m, w, h)
local radius = math.min(w, h) * 0.48
m:Draw(function()
MGFX.Circle(w * 0.5, h * 0.5, radius, color_white)
end)
m:Subtract(function()
MGFX.Circle(w * 0.69, h * 0.31, radius * 0.38, color_white)
end)
end)
MGFX.Clip(badgeMask, x, y, 120, 72, function()
MGFX.Image(x - 16, y, 152, 72, material)
MGFX.Text("READY", "DermaLarge", x + 60, y + 36, color_white,
TEXT_ALIGN_CENTER, TEXT_ALIGN_CENTER)
end)The recorder supports exact coverage operations:
| Operation | Coverage formula |
|---|---|
Draw / Union |
max(A, B) |
Subtract |
A * (1 - B) |
Intersect |
A * B |
Xor |
A + B - 2AB |
Invert |
1 - A inside the current bounds |
Built-in analytical presets include Masks.Circle, Masks.Capsule,
Masks.Rounded(...), and Masks.Chamfer(...). Custom coverage is rasterized
into local bucketed accumulator/scratch targets and cached. Integer translation
normally reuses the raster; call mask:Invalidate() when painter inputs change.
Supported shapes can also clip their own children without repeating a Mask:
MGFX.RoundedBoxEx(x, y, w, h, {
radius = 18,
fill = Color(8, 18, 24, 230),
stroke = Color(100, 220, 170, 180),
strokeWidth = 2,
}, function(cx, cy, cw, ch)
MGFX.ImageEx(cx, cy, cw, ch, material, {fit = "cover"})
end)The container order is background/effects → clipped children → foreground stroke, so children cannot cover the foreground border.
Coverage Clip is antialiased and does not use stencil or a binary fallback. It is a framebuffer transaction, so use the cheaper rectangular scissor stack for ordinary scrolling regions. See the complete Mask and Clip reference for cache, nesting, return-value, and state guarantees.
MGFX can rotate, scale, translate, tilt, and project drawing without taking ownership of layout or input mapping.
local lift = MGFX.Transform({
origin = "50% 50%",
rotate = 4,
scale = 1.02,
translate = {x = 0, y = -2},
})
MGFX.RoundedBoxEx(x, y, w, h, {
radius = 12,
fill = Color(12, 20, 28, 220),
transform = lift,
})Use PushTransform / PopTransform to apply one transform to multiple draws.
PointerTilt and ProjectedQuad cover common 2.5D presentation cases.
Transforms are visual only; callers remain responsible for matching hit tests
and interaction coordinates.
MGFX optimizes immediate rendering rather than hiding all work behind a large general batching scheduler. Garry's Mod UI time is often lost to temporary tables, repeated normalization, material parameter churn, and unnecessary Source API calls—not draw count alone.
- Keeps common shape calls direct and immediate
- Parses public style tables once at the API boundary
- Passes prepared scalar/fill/stroke/effect values through internal layers
- Uploads hot parameters through shared matrix pages instead of many floats
- Reuses Matrix objects and material state
- Pools temporary frame, command, and rectangular-clip records
- Fuses only effect combinations that remain visually equivalent
- Caches pattern seeds, text measurements, glyph runs, and reusable coverage
- Offers allocation-light
RoundedBoxBackdrop,LineNoCaps, andImageUV - Keeps readable CPU fallback routes where fidelity can degrade safely
Stable styles can be normalized once:
local style = MGFX.CompileStyle({
radius = 12,
fill = Color(15, 22, 30, 235),
backdrop = {blur = 8, tint = Color(5, 12, 18, 100)},
})For N blurred backdrop shapes at one level with no forced recapture:
MGFX: 1 framebuffer capture + 2 separable blur passes + N masked samples
Naive path: N framebuffer captures + 2N blur passes + N masked samples
This reuse is level- and frame-specific; it does not make blur free.
A representative complex shop UI with many rounded surfaces, gradients, strokes, shadows, glows, images, and text rows recently held:
Full item list stable 130+ FPS
Lighter categories stable 160+ FPS
These are local in-game observations, not universal guarantees. A useful benchmark should also report resolution, GPU/CPU, FPS cap/VSync, other HUD and addon workload, median frame time, tail frame times, and enabled diagnostics. Disable profiling and draw counters before measuring normal production cost.
See Performance Notes for the practical checklist and current architecture.
Use lua-mgfx/ as the addon root:
garrysmod/
└── addons/
└── mgfx/
├── lua/
├── materials/
├── resource/
└── addon.json
The library entry is explicit on the client:
local mgfx = include("mgfx/init.lua")Do not manually include cl_mgfx*.lua implementation files. The bundled
autorun files preserve the legacy global-addon behavior for existing installs.
Install the public package from the repository root:
luxc install @lux/mgfx --from github:TimeWatcher/lux-mgfx --tag v0.1.0Or use a local checkout:
luxc install @lux/mgfx --from C:\Development\gmod\lux-mgfximport * as mgfx from "@lux/mgfx"
local draw = mgfx.api
draw.roundedBox(...)
draw.roundedBoxEx(...)
draw.imageEx(...)
draw.textEx(...)
The facade initializes its default runtime lazily. Import installGlobal from
@lux/mgfx/global only when non-Lux code intentionally needs the global
GLua-style table. Application code should not import primitive, widget, text,
or style internals as separate rendering entry points.
local mgfx = include("mgfx/init.lua")
function PANEL:Paint(w, h)
mgfx.StartPanel(self, w, h)
mgfx.RoundedBoxEx(0, 0, w, h, {
radius = 10,
fill = mgfx.LinearGradient(0, 0, 1, 1,
Color(18, 28, 38, 235),
Color(8, 14, 22, 240),
"smoothstep"),
shadow = {
x = 0,
y = 6,
blur = 14,
color = Color(0, 0, 0, 110),
},
})
mgfx.ProgressBarEx(16, h - 24, w - 32, 8, 0.72, {
radius = 4,
track = Color(255, 255, 255, 18),
fill = mgfx.LinearGradient(0, 0, 1, 0,
Color(72, 220, 138),
Color(120, 255, 186)),
})
mgfx.Text("READY", "DermaDefaultBold", 16, 18, color_white,
TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
mgfx.EndPanel()
endStartPanel makes coordinates panel-local. Use StartScreen / EndScreen
for HUDPaint and screen-space overlays. Direct primitive calls remain valid
when coordinated frame state is not needed.
Install mgfx/devtools.lua (Plain GLua) or @lux/mgfx/devtools (Lux) to enable
the client commands below:
| Command | Purpose |
|---|---|
mgfx_status |
Shader mount, draw, blur, Clip, gradient, text, and material status |
mgfx_selftest |
Validate the installed public API and runtime invariants |
mgfx_stroke_demo |
Compare solid and patterned stroke variants |
mgfx_profile_status |
Print rolling profiler totals |
mgfx_profile_panels |
Inspect panel/screen scope costs |
mgfx_profile_hud |
Toggle the profiling overlay |
mgfx_profile_reset |
Reset profiler samples |
mgfx_text_status |
Inspect text composer/cache state |
mgfx_text_cache_clear |
Clear text measurement/cache state |
mgfx_text_atlas |
Inspect composed text atlas contents |
The separate example loaders add mgfx_demo, mgfx_perf_demo, and
mgfx_wheel_demo; they are not part of devtools or the default entry path.
Useful client CVars:
mgfx_force_fallback 0/1
mgfx_profile 0/1
mgfx_profile_window 120
mgfx_profile_top 18
mgfx_draw_counts 0/1
mgfx_text_composed 0/1
mgfx_text_composed_budget 6
Profiling and draw counters are opt-in because observation has a cost.
Shader rendering is the normal path. Capability detection and readable CPU fallbacks keep basic interfaces usable when shaders are missing, disabled, or unsupported on a platform.
PrintTable(MGFX.ShaderStatus())
if MGFX.Supports(MGFX.TARGET.TEXT, "gradient") then
-- Use composed display text.
endFallbacks may simplify procedural patterns, exact blur softness, glow, or text
composition. APIs that cannot degrade without violating their contract fail
explicitly instead: reusable coverage Clip, for example, has no stencil or
binary-edge fallback.
The shared source lives in docs/:
npm install
npm run docs:dev
npm run docs:buildThe local VitePress output is written to docs-site/. The public Pages site is
published from the separate mgfx-docs-site repository.
MGFX embeds compiled Source .vcs shaders in a Lua/Lux shaderpack that the
runtime mounts as a temporary GMA.
From the repository root:
python .\lua-mgfx\shadersrc\mgfx\build.py
python .\lux-mgfx\lux\mgfx\shadersrc\build.pyBoth source trees must remain synchronized when shared HLSL behavior changes. The SDK helper tools are build-time infrastructure and must not ship in the runtime addon.
.\lux-mgfx\tools\build-precompiled.ps1The plain tree is intended to be GMA-valid:
gmad.exe create -folder ".\lua-mgfx" -out "$env:TEMP\mgfx.gma"lua-mgfx/addon.json excludes shader source, build tools, and Markdown from
the published runtime package.
docs/ Shared English and Chinese documentation source
lua-mgfx/ Canonical Plain GLua addon and its shader source
lux-mgfx/ Lux packages, shader source/tools, and generated distribution
scripts/ Shared repository/documentation tooling
package.json
lux.package.toml
README.md
LICENSE*
NOTICE
lux-mgfx/dist/lua is the Lux-generated loader distribution. It does not
replace lua-mgfx/ as the canonical non-Lux implementation.
- Public draw calls remain immediate and explicit.
- Public style tables are normalized at the API boundary.
- Internal hot layers receive prepared values instead of repeatedly copying and normalizing style records.
- Common drawing calls avoid per-frame allocation.
- Patterns remain shader paint fields rather than geometry recipes.
- Coverage clipping uses continuous shader coverage, never stencil emulation.
- Native text stays the default for ordinary operational labels.
- Shader text is reserved for effects that need composition.
- Render-target, camera, matrix, scissor, blend, and alpha-write mutations use symmetric protected cleanup paths.
- Plain GLua, Lux, generated output, shaderpacks, Ashline integrations, and docs stay synchronized when shared behavior changes.
- A general batching layer requires representative in-game evidence, not only a synthetic microbenchmark.
- Online documentation
- Plain GLua quick start
- Lux quick start
- Core concepts
- Effects
- Coverage Masks and antialiased Clip
- Complete Mask and Clip API
- API reference
- Performance notes
- Internal architecture
- Text renderer
- Shader build and packaging
- Changelog
- Reusable antialiased coverage Masks with exact Boolean composition
- Shape self-clipping callbacks and foreground stroke ordering
- Local bucketed custom-Mask accumulator/scratch targets
- Elliptical radial gradients for top-origin and anisotropic light fields
- Shader-native gradient curves, 16-bit stops LUTs, and stable dithering
- Mathematically fitted patterned-stroke periods and corrected start phases
- Centered
solid,dot,dash, anddot-dashstrokes across shape families - Layered and shared backdrop blur
- Layered shadows and compatible shadow/outer-glow fusion
- Prepared style records and allocation-light raw helpers
- Native text measurement and per-character layout caching
- Failure-safe Clip render-state transactions and idempotent runtime install
- Synchronized Plain GLua, Lux, shaderpack, Ashline, and bilingual docs output
For exact implementation history, see the commit log.
- Panel, flex, or grid layout
- Input dispatch and focus management
- Navigation and component state
- Data binding and animation timelines
- Panel lifecycle
- Hit testing and interaction-coordinate transforms
Use MGFX beneath Derma, a custom component system, Lux UI code, or an existing gamemode framework. Keeping this boundary narrow is what lets MGFX focus on rendering quality and predictable cost.
MGFX source under lux-mgfx/lux/mgfx/, lua-mgfx/lua/mgfx/, and the shader
tooling is available under the Lux MGFX Community License 1.1. Community
servers operated without owner profit may recover reasonable operating costs
through voluntary donations, crowdfunding, and sponsor acknowledgments. Free
plugin development and distribution are also permitted. Commercial server
monetization, paid plugins, and client work require separate written
authorization.
Documentation prose is available under CC BY 4.0. Documentation code examples are licensed MIT OR Apache-2.0. Branding assets are not licensed for reuse by those licenses.
Review LICENSE, LICENSE-MGFX-COMMUNITY, and
NOTICE before distribution or commercial integration.
Built for Garry's Mod interfaces that need more than another stack of boxes. ✦

