Component.GUI namespace contains FFXIV’s entire UI framework, known as the ATK (Addon Toolkit) system. This is the core rendering and interaction system for all UI elements in the game.
Overview
The ATK system is a hierarchical UI framework where:- AtkUnitBase - Base class for all visible UI windows (addons)
- AtkResNode - Base class for all UI elements (nodes)
- AtkComponentBase - Complex UI controls (buttons, lists, etc.)
- AtkEventListener - Event handling interface
Architecture
UI Hierarchy
AtkUnitBase (e.g., AddonCharacter)
├── UldManager
│ ├── NodeList
│ ├── Assets
│ └── PartsList
├── RootNode (AtkResNode)
│ ├── ChildNode (AtkImageNode)
│ ├── ChildNode (AtkTextNode)
│ └── ChildNode (AtkComponentNode)
│ └── Component (AtkComponentButton)
└── WindowNode (AtkComponentNode)
AtkUnitBase
Base class for all visible UI objects (addons). Every UI window inherits from this.Key Structure
public unsafe partial struct AtkUnitBase : ICreatable {
[FieldOffset(0x8)] internal FixedSizeArray32<byte> _name;
[FieldOffset(0x28)] public AtkUldManager UldManager;
[FieldOffset(0xC8)] public AtkResNode* RootNode;
[FieldOffset(0xD0)] public AtkCollisionNode* WindowCollisionNode;
[FieldOffset(0x120)] public AtkComponentNode* WindowNode;
[FieldOffset(0x178)] public AtkValue* AtkValues;
[FieldOffset(0x1E2)] public ushort AtkValuesCount;
[FieldOffset(0x1E4)] public ushort Id;
[FieldOffset(0x1D4)] public short X;
[FieldOffset(0x1D6)] public short Y;
[FieldOffset(0x1ED)] public byte Alpha;
}
Common Operations
Getting Nodes
// Get node by ID
var node = unitBase->GetNodeById(1001);
// Get specific node types
var textNode = unitBase->GetTextNodeById(2);
var imageNode = unitBase->GetImageNodeById(3);
var button = unitBase->GetComponentButtonById(4);
Showing/Hiding
// Show the addon
unitBase->Show(disableShowTransition: false, unsetShowHideFlags: 0);
// Hide the addon
unitBase->Hide(disableHideTransition: false, callCloseCallback: false, setShowHideFlags: 0);
// Check visibility
if (unitBase->IsVisible) {
// Addon is visible
}
Positioning & Scaling
// Set position
unitBase->SetPosition(100, 200);
// Get position
short x = unitBase->GetX();
short y = unitBase->GetY();
// Set scale
unitBase->SetScale(1.5f, a3: true);
// Set alpha
unitBase->SetAlpha(200); // 0-255
Callbacks & Events
// Fire callback with single int value
unitBase->FireCallbackInt(5);
// Fire callback with AtkValue array
var values = stackalloc AtkValue[2];
values[0].Type = ValueType.Int;
values[0].Int = 123;
values[1].Type = ValueType.String;
values[1].String = &myString;
unitBase->FireCallback(2, values);
Virtual Functions
Key virtual functions for addon lifecycle:// Lifecycle
virtual void Initialize(); // VF 41
virtual void Finalizer(); // VF 42
virtual void Update(float delta); // VF 43
virtual void Draw(); // VF 44
virtual void OnSetup(uint valueCount, AtkValue* values); // VF 49
virtual bool OnRefresh(uint valueCount, AtkValue* values); // VF 51
// State management
virtual bool Open(uint depthLayer); // VF 3
virtual bool Close(bool fireCallback); // VF 4
virtual void Show(bool disableShowTransition, uint unsetShowHideFlags); // VF 5
virtual void Hide(bool disableHideTransition, bool callCloseCallback, uint setShowHideFlags); // VF 6
// Input handling
virtual bool HandleCustomInput(AtkEventData.AtkInputData* inputData); // VF 57
virtual void OnFocusChange(bool isFocused); // VF 59
AtkResNode
Base class for all UI nodes (visual elements).Node Structure
public unsafe partial struct AtkResNode : ICreatable {
[FieldOffset(0x8)] public uint NodeId;
[FieldOffset(0x20)] public AtkResNode* ParentNode;
[FieldOffset(0x28)] public AtkResNode* PrevSiblingNode;
[FieldOffset(0x30)] public AtkResNode* NextSiblingNode;
[FieldOffset(0x38)] public AtkResNode* ChildNode;
[FieldOffset(0x40)] public NodeType Type;
[FieldOffset(0x42)] public ushort ChildCount;
[FieldOffset(0x44)] public float X;
[FieldOffset(0x48)] public float Y;
[FieldOffset(0x4C)] public float ScaleX;
[FieldOffset(0x50)] public float ScaleY;
[FieldOffset(0x54)] public float Rotation; // radians
[FieldOffset(0xA0)] public ushort Width;
[FieldOffset(0xA2)] public ushort Height;
[FieldOffset(0xAE)] public NodeFlags NodeFlags;
}
Node Types
public enum NodeType : ushort {
Res = 1, // Basic node
Image = 2, // Image/texture node
Text = 3, // Text node
NineGrid = 4, // Scalable border node
Counter = 5, // Numeric counter
Collision = 8, // Collision detection node
ClippingMask = 10, // Clipping mask
Component = 10000 // Component node
}
Node Flags
[Flags]
public enum NodeFlags : ushort {
AnchorTop = 0x01,
AnchorLeft = 0x02,
AnchorBottom = 0x04,
AnchorRight = 0x08,
Visible = 0x10, // Controls visibility
Enabled = 0x20, // Button can be clicked, etc.
Clip = 0x40,
Fill = 0x80,
HasCollision = 0x100,
RespondToMouse = 0x200,
Focusable = 0x400,
Droppable = 0x800,
IsTopNode = 0x1000,
EmitsEvents = 0x2000,
UseDepthBasedPriority = 0x4000,
}
Common Node Operations
// Position
node->SetPositionFloat(100.0f, 200.0f);
node->SetPositionShort(100, 200);
// Size
node->SetWidth(300);
node->SetHeight(150);
// Visibility
node->ToggleVisibility(true);
if (node->IsVisible()) { /* ... */ }
// Scale
node->SetScale(1.5f, 1.5f);
// Rotation (in radians)
node->SetRotation(3.14159f);
node->SetRotationDegrees(180.0f);
// Alpha
node->SetAlpha(128); // 0-255
Event System
// Add event listener
node->AddEvent(
AtkEventType.MouseClick,
eventParam: 0,
listener: myListener,
nodeParam: null,
isGlobalEvent: false
);
// Remove event
node->RemoveEvent(
AtkEventType.MouseClick,
eventParam: 0,
listener: myListener,
isGlobalEvent: false
);
// Check if event is registered
if (node->IsEventRegistered(AtkEventType.MouseClick)) {
// Event is registered
}
AtkTextNode
Node type for displaying text.Structure
public unsafe partial struct AtkTextNode : ICreatable {
[FieldOffset(0xC0)] public uint TextId;
[FieldOffset(0xC4)] public ByteColor TextColor;
[FieldOffset(0xC8)] public ByteColor EdgeColor;
[FieldOffset(0xCC)] public ByteColor BackgroundColor;
[FieldOffset(0xD0)] public Utf8String NodeText;
[FieldOffset(0x162)] public byte LineSpacing;
[FieldOffset(0x163)] public byte CharSpacing;
[FieldOffset(0x164)] public byte AlignmentFontType;
[FieldOffset(0x165)] public byte FontSize;
[FieldOffset(0x170)] public TextFlags TextFlags;
}
Usage
// Set text
textNode->SetText("Hello World");
textNode->SetText(myUtf8String);
// Get text
var text = textNode->GetText();
// Set number
textNode->SetNumber(1234, showCommaDelimiters: true, showPlusSign: false);
// Set alignment
textNode->SetAlignment(AlignmentType.Center);
// Set font
textNode->SetFont(FontType.Jupiter);
// Resize node to fit text
textNode->ResizeNodeForCurrentText();
// Get text dimensions
ushort width, height;
textNode->GetTextDrawSize(&width, &height);
Text Flags
[Flags]
public enum TextFlags : ushort {
AutoAdjustNodeSize = 1 << 0,
Bold = 1 << 1,
Italic = 1 << 2,
Edge = 1 << 3, // Text outline
Glare = 1 << 4,
Emboss = 1 << 5,
WordWrap = 1 << 6,
MultiLine = 1 << 7,
OverflowHidden = 1 << 8,
FixedFontResolution = 1 << 9,
Ellipsis = 1 << 10,
}
Font Types
public enum FontType : byte {
Axis = 0,
MiedingerMed = 1,
Miedinger = 2,
TrumpGothic = 3,
Jupiter = 4,
JupiterLarge = 5,
}
AtkImageNode
Node type for displaying images and textures.Structure
public unsafe partial struct AtkImageNode : ICreatable {
[FieldOffset(0xC0)] public AtkUldPartsList* PartsList;
[FieldOffset(0xC8)] public ushort PartId;
[FieldOffset(0xCA)] public byte WrapMode;
[FieldOffset(0xCB)] public ImageNodeFlags Flags;
}
Usage
// Load texture from file
imageNode->LoadTexture("ui/icon/000000/000001_hr1.tex");
// Load icon by ID
imageNode->LoadIconTexture(iconId: 1, language: 0);
// Unload texture
imageNode->UnloadTexture();
Image Flags
[Flags]
public enum ImageNodeFlags : byte {
FlipH = 0x01, // Flip horizontally
FlipV = 0x02, // Flip vertically
AutoFit = 0x80, // Auto-fit texture
}
AtkComponentBase
Base class for complex UI components (buttons, lists, etc.).Structure
public unsafe partial struct AtkComponentBase : ICreatable {
[FieldOffset(0x08)] public AtkUldManager UldManager;
[FieldOffset(0x98)] public uint ComponentFlags;
[FieldOffset(0xA0)] public AtkResNode* AtkResNode;
[FieldOffset(0xA8)] public AtkComponentNode* OwnerNode;
}
Component Types
public enum ComponentType : byte {
Base = 0,
Button = 1,
Window = 2,
CheckBox = 3,
RadioButton = 4,
GaugeBar = 5,
Slider = 6,
TextInput = 7,
NumericInput = 8,
List = 9,
DropDownList = 10,
Tab = 11,
TreeList = 12,
ScrollBar = 13,
ListItemRenderer = 14,
Icon = 15,
IconText = 16,
DragDrop = 17,
GuildLeveCard = 18,
TextNineGrid = 19,
JournalCanvas = 20,
Multipurpose = 21,
Map = 22,
Preview = 23,
HoldButton = 24,
Portrait = 25,
}
Component Operations
// Get nodes within component
var node = component->GetNodeById(1);
var textNode = component->GetTextNodeById(2);
var imageNode = component->GetImageNodeById(3);
// Get nested components
var nestedComponent = component->GetComponentById(4);
// Enable/disable
component->SetEnabledState(true);
AtkComponentButton
Button component.Structure
public unsafe partial struct AtkComponentButton : ICreatable {
[FieldOffset(0xC8)] public AtkTextNode* ButtonTextNode;
[FieldOffset(0xD0)] public AtkResNode* ButtonBGNode;
[FieldOffset(0xE8)] public uint Flags;
}
Usage
// Set button text
button->SetText("Click Me");
// Check if enabled
if (button->IsEnabled) {
// Button is enabled
}
// For checkboxes/radio buttons
button->SetChecked(true);
if (button->IsChecked) {
// Button is checked
}
AtkComponentList
Scrollable list component.Structure
public unsafe partial struct AtkComponentList : ICreatable {
[FieldOffset(0xC8)] public AtkComponentScrollBar* ScrollBarComponent;
[FieldOffset(0xF0)] public ListItem* ItemRendererList;
[FieldOffset(0x120)] public int ListLength;
[FieldOffset(0x134)] public int SelectedItemIndex;
[FieldOffset(0x138)] public int HeldItemIndex;
[FieldOffset(0x13C)] public int HoveredItemIndex;
[FieldOffset(0x186)] public short ItemWidth;
[FieldOffset(0x188)] public short ItemHeight;
}
Usage
// Set item count
list->SetItemCount(10);
// Set item text
list->SetItemLabel(0, "First Item");
list->SetItemLabel(1, "Second Item");
// Set item icon
list->SetItemIcon(0, iconId: 66001);
// Select item
list->SelectItem(2, dispatchEvent: true);
// Deselect
list->DeselectItem();
// Scroll to item
list->ScrollToItem(5);
list->CenterScrollOnItem(5);
// Get item state
var isDisabled = list->GetItemDisabledState(0);
var isHighlighted = list->GetItemHighlightedState(0);
// Set item state
list->SetItemDisabledState(0, disabled: true);
list->SetItemHighlightedState(1, highlighted: true);
Event Types
public enum AtkEventType : byte {
// Mouse events
MouseDown = 3,
MouseUp = 4,
MouseMove = 5,
MouseOver = 6,
MouseOut = 7,
MouseWheel = 8,
MouseClick = 9,
MouseDoubleClick = 10,
// Input events
InputReceived = 12,
InputNavigation = 13,
// Focus events
FocusStart = 18,
FocusStop = 19,
// Button events
ButtonPress = 23,
ButtonRelease = 24,
ButtonClick = 25,
// List events
ListItemRollOver = 33,
ListItemRollOut = 34,
ListItemClick = 35,
ListItemDoubleClick = 36,
ListItemSelect = 38,
// Drag & Drop events
DragDropBegin = 50,
DragDropEnd = 51,
DragDropInsert = 53,
DragDropDiscard = 57,
DragDropClick = 58,
// Timeline events
TimelineActiveLabelChanged = 74,
// Text link events
LinkMouseClick = 75,
LinkMouseOver = 76,
LinkMouseOut = 77,
}
AtkUldManager
Manages ULD (UI Layout Data) resources and node creation.Structure
public unsafe partial struct AtkUldManager {
[FieldOffset(0x00)] public AtkUldAsset* Assets;
[FieldOffset(0x08)] public AtkUldPartsList* PartsList;
[FieldOffset(0x10)] public AtkUldObjectInfo* Objects;
[FieldOffset(0x50)] public AtkResNode** NodeList;
[FieldOffset(0x42)] public ushort NodeListCount;
[FieldOffset(0x78)] public AtkResNode* RootNode;
}
Usage
// Search for node by ID
var node = uldManager->SearchNodeById(1001);
// Create nodes
var resNode = AtkUldManager.CreateAtkResNode();
var imageNode = AtkUldManager.CreateAtkImageNode();
var textNode = AtkUldManager.CreateAtkTextNode();
// Create components
var button = uldManager->CreateAtkComponent(ComponentType.Button);
var list = uldManager->CreateAtkComponent(ComponentType.List);
Example: Modifying an Addon
// Get the Character addon
var addon = (AddonCharacter*)AtkStage.Instance()->RaptureAtkUnitManager->GetAddonByName("Character");
if (addon == null || !addon->AtkUnitBase.IsVisible) return;
// Get a text node and update it
var textNode = addon->AtkUnitBase.GetTextNodeById(5);
if (textNode != null) {
textNode->SetText("Custom Text");
textNode->TextColor = new ByteColor { R = 255, G = 100, B = 100, A = 255 };
}
// Get a button and modify it
var button = addon->AtkUnitBase.GetComponentButtonById(10);
if (button != null) {
button->SetText("Custom Button");
button->AtkComponentBase.SetEnabledState(true);
}
// Move the addon
addon->AtkUnitBase.SetPosition(100, 200);
Best Practices
- Always null-check: Nodes and components may not exist
- Respect visibility: Check
IsVisiblebefore modifying - Use correct node types: Cast nodes to their specific type
- Memory safety: Nodes are unmanaged - don’t store pointers long-term
- Event handling: Clean up event listeners properly
- Text lifetime: Text pointers must remain valid (see SetText documentation)
See Also
- Client.UI - Addon implementations
- Component.Excel - Game data access
- Component.Text - Text processing