Repository navigation
Architecture
How Lumina UI works inside.
On this page: Core idea · Core layers (io.github.ssbaxys.lumina) · How it meets the requirements
The whole UI (widget tree, layout, styles, animations, events) lives in the core module,
pure Java 17 without a single Minecraft class. Loader modules are thin: they only implement
primitive drawing, input forwarding and the mod entry point.
core/ pure Java 17, unit tests without launching the game
forge-1.20.1/ Forge 47, Java 17 (ModDevGradle legacyforge)
src/main/ the luminaui library
src/testmod/ the luminatest test mod (entry points)
neoforge-1.21.1/ NeoForge 21.1, Java 21 (ModDevGradle)
src/main/, src/testmod/
testmod-common/ showcase: test mod pages on the core API + a run without the game
The core sources are compiled straight into each loader's jar, so the output is one mod
with no nested libraries. Adding a new game version means copying a loader module
(~7 small files) and adjusting the rendering API.
| Package | What it does |
|---|---|
render |
Canvas (drawing interface for widgets), AbstractCanvas (transform stack, clip, opacity, culling), Brush (solid and gradients), ColorStops, ColorSpace, Gradients, BlendMode, Radii, Shadow, Outline, Color
|
layout |
Two-pass measure/arrange layout: FlexLayout (flexbox: gap, grow/shrink, justify, align), StackLayout (layers), absolute positioning, Dim (auto / px / % / fill) |
node |
UiElement (tree node), UiRoot (root: hover, presses, focus, Tab navigation, event dispatch, frame) |
style |
StyleKey (typed properties with dense ids), Style (values + variants for hover/pressed/focused/disabled/checked), ComputedStyle (current values, per-property transitions, animation layer), Theme (class styles and ThemeVar/Tokens tokens), Transition
|
anim |
Animator (keeps only active animations), AnimatedFloat (tween or spring), Easing (23 curves, cubic-bezier, steps, spring), Interpolator, Motion (timeline: sequence/parallel/delay/call), Keyframes, Tween, Playback (loops, yoyo, speed) |
event |
Typed events with capture and bubble phases: mouse, wheel, keyboard, characters, focus |
reactive |
Signal, Computed (automatic dependency tracking) for binding data to widgets |
widget |
Widget<S> (type-safe fluent API), Panel, Label, Button, ScrollPanel, Toggle, Slider, ProgressBar, RingProgress, ColorPicker
|
fx |
FxLayer (effects layer), Particles (particles in flat arrays), SpriteSheet, VanillaFx (fire, explosion, TNT, lava, smoke, shake on vanilla textures) |
markdown |
MarkdownParser → Md tree → MarkdownLayout (flat draw operations) → Markdown widget |
i18n |
I18n: current language as a signal, live tr(...) translations, tables from code and the game's lang files, language list; LanguageButton is a ready switcher |
platform |
Platform: everything the core needs from the game (font metrics, clipboard, sound, time, language and lang files, settings) |
No reflection. The platform is passed explicitly (Lumina.init(platform)), without ServiceLoader.
Style properties and event types get integer ids on registration, so values
and listeners live in arrays by index. Extending (your own properties, events, layouts,
widgets) is plain code: StyleKey.builder(...).register(), EventType.create(...),
implements Layout, extends Widget<MyWidget>.
Performance.
- Layout is cached and recomputed only after
invalidateLayout(), and only along the ancestor chain. - The style for each state combination is computed once and cached in
Style; a hover change costs O(1). - Inherited properties (text color) are not copied down the tree but read lazily from the parent.
-
AbstractCanvaskeeps its state in a flat float array, drops invisible primitives and changes the scissor only when the clip really changes. A frame is drawn with almost no allocations. - Plain rectangles are collected into one buffer and drawn in one call.
- The animator is empty at rest: no work if nothing moves.
- A subtree that is fully invisible (off screen or outside a scroll area) is not traversed at all.
Elements that draw outside their bounds get
setOverflowsBounds(true).
Looks. Rounded corners (different radius per corner), borders and soft shadows are drawn by an SDF shader
(assets/luminaui/shaders/core/rounded_rect.*) with anti-aliasing of exactly one physical pixel
at any GUI scale. Gradients, opacity and scale are inherited down the tree. Transitions between
states (hover, press, focus) are animated from the theme style.
Flexibility. The theme sets styles by widget class (several classes allowed), the inline style goes on top. Styles reference theme tokens, so changing one token smoothly recolors the whole UI.Any layout and any widget can be replaced with your own. Signals bind data to the UI.
Начало работы: Установка · Первый экран
Основы: Раскладка · Стили и темы · Цвета и градиенты · Анимации · Данные и сигналы · События и ввод
Виджеты: Каталог виджетов · Всплывающие окна · Формы · Markdown и книги
Игра: Инвентарь и слоты · Окна-контейнеры · Мобы, предметы и 3D · HUD · Карты
Оформление: Эффекты · Размытие, обрезка и GIF
HTML и CSS: HTML и CSS
Возможности: Языки · Экран настроек · Доступность и звуки
Для продвинутых: Расширение · Отладка и советы · Архитектура
Getting started: Installation · Your First Screen
Basics: Layout · Styles and Themes · Colors and Gradients · Animations · Data and Signals · Events and Input
Widgets: Widget Catalog · Popups · Forms · Markdown and Books
Game: Inventory and Slots · Container Screens · Mobs, Items and 3D · HUD Overlay · Maps
Visuals: Effects · Blur, Clipping and GIF
HTML and CSS: HTML and CSS
Features: Languages · Config Screen · Accessibility and Sounds
Advanced: Extending · Debugging and Tips · Architecture