Workflow
The whole loop of authoring a screen — text and designer writing back to each other, save-to-recompile, placing it on the screen or in the world, wiring interaction, animating, and looking when something is off.
One file, two ways in
A text-authored widget Blueprint has one truth: its .dui. There are two ways to change it, and both always see the
same thing.
- In the text. Open it in VS Code (Tools ▸ Open DreamUI Workspace (VSCode) rewrites
DUI/DreamUI.code-workspacefrom the current source roots and opens it, falling back to Notepad when VS Code is unavailable). The extension's completion comes from theDUI/.dui-symbols.jsonthe editor writes; see VS Code extension. - In the designer. The designer is a front end for the file: a change made there is a change to the text, written
into the line that holds the value — or a new line after the node's others — with everything else byte for byte as
it was. A few changes have no line to write into — the visibility of a widget an
ifshows or hides, for one — and the designer says so (DUI7004) instead of inventing one. See Write-back.
Save to recompile
Save a .dui in an outside editor and the loaded classes built from it recompile. An editor writes a file more than
once per save, so changes are collected for a moment (0.75 seconds) before anything happens.
- A failed compile shows a notification with an Open the file link to the file that failed.
- More than 8 files changing at once (a branch switch, a bulk rewrite) is not compiled unasked; a notification offers Rebuild them now. The files are kept, not dropped — dropping them would leave those classes stale with nothing to say so.
- A source file deleted or renamed gets a notification naming the classes now built from nothing.
- Tools ▸ Rebuild DUI recompiles every text-backed widget Blueprint in the project, loading the ones that are not, and asks first.
A diagnostic reads File.dui(line,col): error DUI3001: …, and its first digit says which stage refused: 1 lexer,
2 parser, 3 meaning, 4 values, 5 building the tree, 6 compiling into the Blueprint, 7 writing back. Every one is in
Diagnostics with its cause and fix.
The shape of a day
Write
Write the tree in VS Code or in the designer: nodes, properties, styles, components. A new file can start from the
designer's Create Source File..., which writes a .dui with a starter hierarchy. Reuse is by component: after
use "Components/Row.dui" as Row, Row Audio { … } is an instance of that class (see
Components).
Compile
Save. The designer's preview follows. On an error, read the notification and the line and column in the diagnostic.
Place
On the screen: UDreamUIBPLibrary::AddWidgetOfClassToViewport. In the world: drag the widget Blueprint into a level
and get an ADreamWorldWidgetActor. One class, both uses, nothing changed in it (see
Your first screen and World space).
Wire up interaction
Events have one mechanism, spelled the same way everywhere: a route. EventName -> Handler names a function on the
user widget — the class the tree compiles into, which is where UMG puts event handling too. The compiler resolves
every route into UDreamWidgetBlueprint::EventBindings, and UDreamUserWidget::BindEventBindings attaches them at
Initialize. In the designer the same thing is the Events section of the details panel: the + creates a custom event
with the right signature and the route that names it. A handler the class lacks is
DUI6004; one whose parameters do not match is
DUI6005.
Properties are driven by bindings: Text <- GetTitle() makes a property follow an expression, Value <-> Volume
mirrors it both ways. See Bindings.
Animate
A timeline block is an animation the file owns: one line per track, with a node path, the property it drives and the
keys. It compiles into a UDreamWidgetAnimation in the root's animation component, gets its class member variable like
any other animation, and plays through UDreamUserWidget::PlayAnimation. Because the file owns it, every compile
rebuilds it and the animation editor opens it read-only; to hand an animation to Sequencer for good, write
timeline Name external. Inside a panel, animate a component through its render-transform tweens (RenderOffsetTo,
RenderScaleTo, RenderAngleTo, RenderTranslationTo), which move what is drawn and never the layout. See
Timelines and Animation.
See what it drew, and what it cost
DreamUI.Capture writes a PNG of the viewport and of every render-target canvas; DreamUI.Stats prints what each stage
cost since the last time it was asked; DreamGUI.Memory prints what the fonts, atlases and canvases hold. For something
drawn wrong or not drawn, reproduce it with r.DreamUI.VerifyPartialPrepare 1. See Debugging.
Interaction and animation together, a small pause menu looks like this:
class /Game/UI/WBP_Pause
Widget Root {
AnchorData.AnchorMin = (0, 0)
AnchorData.AnchorMax = (1, 1)
AnchorData.SizeDelta = (0, 0)
+ Overlay {}
Native.Button Resume {
AnchorData.SizeDelta = (240, 56)
@slot HorizontalAlignment = Center
@slot VerticalAlignment = Center
OnClicked -> HandleResume
Text Label { Text = "Resume" }
}
}
timeline Appear {
duration = 0.3
Resume.RenderScale : 0.0 = (0.9, 0.9, 1), 0.3 = (1, 1, 1) ease OutCubic
}Native.Button is the registry tag of the plugin's button control; OnClicked -> HandleResume needs a function or
custom event called HandleResume on WBP_Pause; Appear compiles into an animation with a class member variable of
its own — drag that variable into PlayAnimation to play it.
The designer and the text are two views of one class: there is no apply step, and no per-instance override list to reconcile. Content a parent supplies to a child goes through named slots; see Widget Blueprints.
Project layout
The runtime module layers and what each holds, which module your Build.cs adds, where .dui files live, what each plugin folder is, and the log categories.
How it differs
The structural differences from UMG (text overflow above all), why the names are UMG's and the parity tables, which upstream commit the fork starts from and what it rebuilt, and credits and license.