PixelUI for ComputerCraft/CC: Tweaked
November 1, 2025 ยท View on GitHub
Important
This framework is now archived due to the release of a newer version. View it here.
A modern, feature-rich, extensible UI framework for ComputerCraft and CC: Tweaked, designed for advanced desktop-style applications, games, and tools. PixelUI brings a full suite of widgets, event handling, animations, and more to your in-game computers.
๐ Super Features
- Comprehensive Widget Library: Buttons, labels, text boxes, checkboxes, sliders, range sliders, progress bars, list views, containers, group boxes, color pickers, color picker dialogs, tab controls, combo boxes, numeric up/down, spinners, loading indicators, scrollbars, modal dialogs, charts, draggable widgets, notification toasts, data grids/tables, and more.
- Background Threads System: Run background tasks while keeping the UI responsive! Perfect for HTTP requests, file processing, and long-running operations.
- Advanced Layouts: Absolute, vertical, horizontal, and smart margin/grid layouts for complex UIs.
- Scrollable Containers: True scrollable containers with automatic scrollbars, strict clipping, and event handling.
- Event System: Mouse, keyboard, scroll, drag, and focus events, with full propagation and focus management.
- Animation Engine: Animate any widget property (position, color, size, etc.) with custom easing, chaining, and callbacks.
- Theming: Fully themeable with color schemes, per-widget overrides, and easy customization.
- Modal & Context Menus: Modal dialogs and context menus that block or overlay the UI as needed.
- Draggable Widgets: Make any widget draggable, with custom drag areas and callbacks.
- Password & Masked Input: Secure text boxes for password entry.
- Pixel Canvas: Draw pixel-level graphics with the Canvas widget.
- Extensible: Easily add your own widgets or extend existing ones.
- Demo Suite: Includes a full-featured demo app showcasing every widget and feature.
๐ฆ Installation
- Download
pixelui.luaand (optionally)example.luato your ComputerCraft computer. - Place
pixelui.luain the same directory as your main program. - In your program, load PixelUI:
local PixelUI = require("pixelui")
If you use the demo, run:
example.lua
๐ ๏ธ Usage & API
1. Initialization
local PixelUI = require("pixelui")
PixelUI.init()
2. Creating Widgets
Widgets are created with PixelUI.<widget>() functions. Example:
PixelUI.label({ x = 2, y = 2, text = "Hello!", color = colors.cyan })
PixelUI.button({ x = 2, y = 4, text = "Click Me", onClick = function() print("Clicked!") end })
3. Containers & Layouts
local container = PixelUI.container({ x = 1, y = 1, width = 20, height = 10, border = true, isScrollable = true })
container:addChild(PixelUI.label({ x = 2, y = 2, text = "Inside!" }))
- Layouts: Set
layout = "vertical"or"horizontal"for auto-arrangement. UseautoMargin = truefor smart spacing.
4. Scrollable Containers
- Set
isScrollable = trueon a container. Add children as usual. If content exceeds the container, scrollbars appear and mouse wheel works.
5. Event Handling
- All widgets support
onClick, and many supportonChange,onSelect,onToggle, etc. - Keyboard and mouse events are handled automatically by
PixelUI.run().
6. Animation
PixelUI.animate(widget, {
to = { x = 10, y = 5, background = colors.red },
duration = 1.0,
easing = "outQuad",
onComplete = function(w) print("Done!") end
})
7. Modal Dialogs
PixelUI.msgBox({
title = "Hello!",
message = "This is a modal dialog.",
buttons = {"OK", "Cancel"},
onButton = function(box, idx, text) print("You chose " .. text) end
})
-- Color picker dialog
local colorDialog = PixelUI.colorPickerDialog({
title = "Choose Color",
selectedColor = colors.blue,
onColorSelected = function(color) print("Selected:", color) end
})
colorDialog:show()
8. Draggable Widgets
PixelUI.button({
x = 5, y = 5, text = "Drag Me!", draggable = true,
dragArea = { x = 1, y = 1, width = 10, height = 1 },
onDragStart = function(self, relX, relY) print("Started drag") end,
onDragEnd = function(self) print("Stopped drag") end
})
9. Theming
PixelUI.setTheme({
primary = colors.purple,
background = colors.black,
button = { background = colors.purple, text = colors.white }
})
๐ Widget Reference (Detailed)
Below is a comprehensive reference for every widget and feature in PixelUI. Each section includes all properties, events, usage examples, and advanced notes.
PixelUI.label(props) โ Static Text
Properties:
x,y: Positiontext: The string to displaycolor: Text color (default: theme.text)background: Background color (optional)align:"left","center","right"(default: left)width: Optional width (for alignment/wrapping)wrap:trueto wrap text (default: false)
Events: None
Example:
PixelUI.label({ x = 2, y = 2, text = "Hello!", color = colors.cyan, align = "center", width = 20 })
Notes:
- Use
wrap = trueandwidthfor multi-line labels.
PixelUI.button(props) โ Clickable Button
Properties:
x,y,width,heighttext: Button labelcolor: Text colorbackground: Button colorborder: Show border (default: true)icon: Optional icon (character or string)draggable: Make button draggabledragArea: Restrict drag area
Events:
onClick(self, x, y, button): Called when clickedonDragStart(self, relX, relY),onDragEnd(self)
Example:
PixelUI.button({ x = 2, y = 4, text = "Click Me", onClick = function() print("Clicked!") end })
Notes:
- Supports keyboard activation if focused.
PixelUI.textBox(props) โ Text Input
Properties:
x,y,widthtext: Initial valueplaceholder: Placeholder textcolor,background,borderpassword: Mask input (for passwords)maxLength: Maximum input lengthreadonly: Prevent editing
Events:
onChange(self, value): On text changeonEnter(self, value): On Enter key
Example:
PixelUI.textBox({ x = 2, y = 6, width = 16, placeholder = "Type here...", onChange = function(self, v) print(v) end })
Notes:
- Use
password = truefor password fields.
PixelUI.checkBox(props) โ Checkbox
Properties:
x,ychecked: Initial state (bool)text: Labelcolor,background
Events:
onToggle(self, checked): When toggled
Example:
PixelUI.checkBox({ x = 2, y = 8, text = "Enable", checked = true, onToggle = function(self, c) print(c) end })
PixelUI.slider(props) โ Slider
Properties:
x,y,widthmin,max,valuecolor,background,barColorshowValue: Show value as text
Events:
onChange(self, value): On value change
Example:
PixelUI.slider({ x = 2, y = 10, width = 20, min = 0, max = 100, value = 50, onChange = function(self, v) print(v) end })
PixelUI.rangeSlider(props) โ Range Slider
Properties:
x,y,widthrangeMin,rangeMax: Overall range boundsminValue,maxValue: Current selected rangestep: Value increment steptrackColor,fillColor,knobColor: ColorsshowValues: Show range values as textvalueFormat: Format string for values (default: "%.0f")
Events:
onChange(self, minValue, maxValue): On range change
Example:
PixelUI.rangeSlider({
x = 2, y = 10, width = 25,
rangeMin = 0, rangeMax = 100,
minValue = 20, maxValue = 80,
onChange = function(self, min, max) print("Range:", min, "-", max) end
})
PixelUI.progressBar(props) โ Progress Bar
Properties:
x,y,widthprogress: 0-100 (percent)color,background,barColortext: Optional label
Events: None
Example:
PixelUI.progressBar({ x = 2, y = 12, width = 20, progress = 75, text = "Loading..." })
PixelUI.listView(props) โ List with Selection
Properties:
x,y,width,heightitems: Array of strings/tablesselected: Index of selected itemmultiSelect: Allow multiple selectioncolor,background,selectedColor
Events:
onSelect(self, idx, item): On selection
Example:
PixelUI.listView({ x = 2, y = 14, width = 20, height = 5, items = {"A", "B", "C"}, onSelect = function(self, idx, item) print(item) end })
PixelUI.container(props) โ Layout/Grouping, Scrollable
Properties:
x,y,width,heightborder: Show borderisScrollable: Enable scrollinglayout:"vertical","horizontal", ornilautoMargin: Smart spacingchildren: Array of widgets
Methods:
addChild(widget),removeChild(widget)
Events: None (children handle their own events)
Example:
local c = PixelUI.container({ x = 1, y = 1, width = 20, height = 10, border = true, isScrollable = true })
c:addChild(PixelUI.label({ x = 2, y = 2, text = "Inside!" }))
Notes:
- Scrollable containers clip children and handle scrollbars automatically.
- Use
layoutfor auto-arrangement.
PixelUI.toggleSwitch(props) โ Modern Toggle
Properties:
x,ychecked: Initial statecolor,backgroundtext: Label
Events:
onToggle(self, checked)
Example:
PixelUI.toggleSwitch({ x = 2, y = 20, checked = true, text = "On/Off" })
PixelUI.radioButton(props) โ Radio Button
Properties:
x,ytext: Labelgroup: Group name (only one selected per group)checked: Initial state
Events:
onSelect(self)
Example:
PixelUI.radioButton({ x = 2, y = 22, text = "Option 1", group = "grp1", checked = true })
PixelUI.comboBox(props) โ Dropdown
Properties:
x,y,widthitems: Array of optionsselected: Indexcolor,background
Events:
onSelect(self, idx, item)
Example:
PixelUI.comboBox({ x = 2, y = 24, width = 16, items = {"Red", "Green", "Blue"}, onSelect = function(self, idx, item) print(item) end })
PixelUI.tabControl(props) โ Tabs
Properties:
x,y,width,heighttabs: Array of tab namesselected: Indexchildren: Array of containers (one per tab)
Events:
onTabChange(self, idx, name)
Example:
PixelUI.tabControl({ x = 2, y = 26, width = 20, height = 8, tabs = {"A", "B"}, children = {tabA, tabB} })
PixelUI.numericUpDown(props) โ Numeric Input
Properties:
x,y,widthmin,max,value,stepcolor,background
Events:
onChange(self, value)
Example:
PixelUI.numericUpDown({ x = 2, y = 28, width = 8, min = 0, max = 10, value = 5, step = 1 })
PixelUI.groupBox(props) โ Visual Grouping
Properties:
x,y,width,heighttext: Optional labelcolor,background,border
Events: None
Example:
PixelUI.groupBox({ x = 2, y = 30, width = 20, height = 6, text = "Group" })
PixelUI.canvas(props) โ Pixel Drawing
Properties:
x,y,width,heightbackground
Methods:
setPixel(x, y, color),getPixel(x, y)
Events: None
Example:
local c = PixelUI.canvas({ x = 2, y = 32, width = 10, height = 5 })
c:setPixel(1, 1, colors.red)
PixelUI.chart(props) โ Data Visualization
Properties:
x,y,width,heightdata: Array of data points (tables with x, y properties or arrays)chartType:"line","bar", or"scatter"(default: "line")title,xLabel,yLabel: Chart labelsbackground,axisColor,dataColor: ColorstitleColor,labelColor,gridColor: Text colorsshowGrid: Show grid lines (default: true)autoScale: Auto-scale axes (default: true)minX,maxX,minY,maxY: Manual axis bounds (when autoScale = false)
Events: None
Example:
local data = {{x=1, y=10}, {x=2, y=25}, {x=3, y=15}, {x=4, y=30}}
PixelUI.chart({
x = 2, y = 5, width = 30, height = 12,
data = data, chartType = "line",
title = "Sample Chart", xLabel = "Time", yLabel = "Value"
})
PixelUI.msgBox(props) โ Modal Dialog
Properties:
title,messagebuttons: Array of button labelscolor,background
Events:
onButton(self, idx, text)
Example:
PixelUI.msgBox({ title = "Hello!", message = "This is a modal dialog.", buttons = {"OK", "Cancel"}, onButton = function(self, idx, text) print(text) end })
PixelUI.colorPicker(props) โ Color Picker
Properties:
x,yselectedColor: Initial colorgridColumns: Number of columns in color grid (default: 4)colorSize: Size of each color swatch (default: 2)showPreview: Show color preview area (default: true)showName: Show color name (default: true)
Events:
onChange(self, color, index, name)
Example:
PixelUI.colorPicker({ x = 2, y = 34, selectedColor = colors.red, onChange = function(self, color, index, name) print(name) end })
PixelUI.colorPickerDialog(props) โ Modal Color Picker Dialog
Properties:
title: Dialog title (default: "Select Color")selectedColor: Initial color selectiononColorSelected: Callback when color is selectedonCancel: Callback when dialog is cancelled
Events:
onColorSelected(color): Called when OK is clicked with selected coloronCancel(): Called when Cancel is clicked or dialog is closed
Methods:
show(): Display the modal dialoghide(): Close the dialog
Example:
local dialog = PixelUI.colorPickerDialog({
title = "Choose Your Color",
selectedColor = colors.blue,
onColorSelected = function(color)
print("Selected color:", color)
-- Apply the color to your widget/application
end,
onCancel = function()
print("Color selection cancelled")
end
})
dialog:show()
Notes:
- Uses an 8-column grid layout for better horizontal space utilization
- Includes color preview swatch and color name display
- Features OK, Cancel, and Reset buttons
- Modal dialog blocks interaction with other UI elements
- Automatically centers on screen
PixelUI.loadingIndicator(props) โ Loading Bar/Spinner
Properties:
x,y,widthprogress: 0-100 (for bar)style:"bar"or"spinner"color,backgroundtext: Optional label
Events: None
Example:
PixelUI.loadingIndicator({ x = 2, y = 36, width = 20, progress = 50, style = "bar", color = colors.cyan, text = "Loading..." })
PixelUI.spinner(props) โ Animated Spinner
Properties:
x,ystyle:"classic","dots", etc.color,backgroundtext: Optional labelactive: Show/hide spinner
Events: None
Example:
PixelUI.spinner({ x = 2, y = 38, style = "classic", color = colors.lime, text = "Processing...", active = true })
PixelUI.scrollBar(props) โ Standalone Scrollbar
Properties:
x,y,lengthorientation:"vertical"or"horizontal"min,max,valuecolor,background,barColor
Events:
onChange(self, value)
Example:
PixelUI.scrollBar({ x = 22, y = 2, length = 10, orientation = "vertical", min = 0, max = 100, value = 50, onChange = function(self, v) print(v) end })
PixelUI.passwordBox(props) โ Password Input
Properties:
- Same as
textBox, but always masked
Events:
- Same as
textBox
Example:
PixelUI.passwordBox({ x = 2, y = 40, width = 16, placeholder = "Password" })
PixelUI.modal(props) โ Custom Modal
Properties:
x,y,width,heightcontent: Widget or containerbackground,border
Events:
- Custom, via content widgets
Example:
PixelUI.modal({ x = 5, y = 5, width = 20, height = 10, content = PixelUI.label({ text = "Custom!" }) })
PixelUI.window(props) โ Windowed UI
Properties:
x,y,width,heighttitle: Window titlecontent: Widget or containerdraggable,resizable
Events:
onClose(self)
Example:
PixelUI.window({ x = 1, y = 1, width = 30, height = 12, title = "My Window", content = PixelUI.label({ text = "Window!" }) })
PixelUI.breadcrumb(props) โ Breadcrumb Navigation
Properties:
x,y,items: Array of stringscolor,background
Events:
onSelect(self, idx, item)
Example:
PixelUI.breadcrumb({ x = 2, y = 42, items = {"Home", "Settings"}, onSelect = function(self, idx, item) print(item) end })
PixelUI.treeView(props) โ Tree View
Properties:
x,y,width,heighttree: Nested table structureselected: Path or index
Events:
onSelect(self, path, node)
Example:
PixelUI.treeView({ x = 2, y = 44, width = 20, height = 8, tree = { {text="Root", children={ {text="Child"} } } }, onSelect = function(self, path, node) print(node.text) end })
PixelUI.spacer(props) โ Layout Spacer
Properties:
width,height
Events: None
Example:
PixelUI.spacer({ width = 2, height = 1 })
PixelUI.notificationToast(props) โ Toast Notifications
Properties:
message: Main notification texttitle: Optional title text (default: "")type: Notification type -"info","success","warning","error"(default: "info")duration: Auto-hide duration in milliseconds (default: 3000)x,y,width,height: Position and sizecloseable: Show close button (default: true)autoHide: Auto-hide after duration (default: true)background,color,titleColor: Custom colors
Events:
onShow(): Called when toast is shownonHide(): Called when toast is hiddenonClick(relX, relY): Called when toast is clicked
Methods:
show(): Display the toast notificationhide(): Hide the toast notification
Example:
local toast = PixelUI.notificationToast({
message = "Operation completed successfully!",
title = "Success",
type = "success",
duration = 4000
})
toast:show()
-- Or use the convenience function
PixelUI.showToast("Hello World!", "Info", "info", 3000)
PixelUI.dataGrid(props) โ Data Table/Grid
Properties:
x,y,width,height: Position and sizecolumns: Array of column definitions withfield,title,widthdata: Array of data rows (objects or arrays)showHeaders: Show column headers (default: true)alternatingRows: Alternate row colors (default: true)gridLines: Show grid lines (default: true)sortable: Enable column sorting (default: true)selectable: Enable row selection (default: true)multiSelect: Allow multiple row selection (default: false)headerColor,headerBackground: Header stylingselectedColor,selectedBackground: Selected row stylingalternateBackground: Alternate row colorgridLineColor: Grid line color
Events:
onRowSelect(rowIndex, rowData): Called when row is selectedonRowDoubleClick(rowIndex, rowData): Called on row double-clickonSort(columnIndex, direction): Called when column is sortedonCellClick(rowIndex, columnIndex, cellData): Called on cell click
Methods:
sortData(): Sort data by current sort columnselectRow(index): Select a specific rowdeselectRow(index): Deselect a specific rowisRowSelected(index): Check if row is selected
Example:
PixelUI.dataGrid({
x = 2, y = 8, width = 45, height = 12,
columns = {
{field = "id", title = "ID", width = 4},
{field = "name", title = "Name", width = 14},
{field = "department", title = "Dept", width = 12}
},
data = {
{id = 1, name = "Alice", department = "Engineering"},
{id = 2, name = "Bob", department = "Marketing"}
},
onRowSelect = function(rowIndex, rowData)
print("Selected:", rowData.name)
end
})
๐จ Theming (Advanced)
PixelUI supports full theming. You can set global or per-widget themes:
PixelUI.setTheme({
primary = colors.purple,
background = colors.black,
button = { background = colors.purple, text = colors.white },
label = { text = colors.yellow },
...
})
- Per-widget themes: Pass
theme = { ... }in widget props to override. - Dynamic theming: Change theme at runtime; widgets update automatically.
๐ Animation Engine (Advanced)
Animate any widget property:
PixelUI.animate(widget, {
to = { x = 10, y = 5, background = colors.red },
duration = 1.0,
easing = "outQuad",
onComplete = function(w) print("Done!") end
})
- Properties: Any numeric/color property can be animated.
- Easing: Supports
linear,inQuad,outQuad,inOutQuad, etc. - Chaining: Animate multiple widgets or properties in sequence.
- Callbacks:
onComplete,onUpdate.
๐ Modal & Context Menus (Advanced)
PixelUI.msgBoxandPixelUI.modalcreate modal dialogs.- Context menus: Use a container with
isModal = trueand custom content. - Modal stacking: Multiple modals can be layered.
๐ฑ๏ธ Drag-and-Drop (Advanced)
- Any widget with
draggable = truecan be dragged. - Use
onDragStart,onDragEnd, andonDropfor custom logic. - Restrict drag area with
dragArea.
๐งต Background Threads System (Advanced)
PixelUI includes a powerful cooperative threading system that allows you to run background tasks while keeping your UI responsive. Perfect for HTTP requests, file operations, and long-running computations!
Quick Start
-- Spawn a simple background task
PixelUI.spawnThread(function()
for i = 1, 100 do
print("Background task progress:", i)
PixelUI.sleep(0.1) -- Yield control back to UI
end
end, "myTask")
-- Run an async operation with automatic cleanup
PixelUI.runAsync(function()
local response = http.get("https://api.example.com/data")
if response then
local data = response.readAll()
response.close()
-- Update UI with the data
myLabel:setText("Received: " .. #data .. " bytes")
end
end)
Thread Management Functions
PixelUI.spawnThread(func, name)
Creates and starts a new background thread.
func: The function to run in the backgroundname: Optional thread name for identification- Returns: Thread ID
PixelUI.killThread(threadId)
Stops and removes a running thread.
threadId: ID of thread to stop
PixelUI.runAsync(func, name)
Convenience function that spawns a thread with automatic error handling.
- Shows toast notifications for errors
- Automatically cleans up on completion
PixelUI.sleep(seconds)
Yields control back to the main UI loop for the specified time.
seconds: Time to sleep (can be fractional)- Must be called from within a thread
Thread System Features
- Cooperative Multitasking: Threads yield control voluntarily, preventing UI freezing
- Automatic Cleanup: Threads are automatically removed when they complete or error
- Error Handling: Uncaught errors show toast notifications and don't crash the UI
- Thread Monitoring: Get thread status and information
- Integration: Works seamlessly with PixelUI's event system and animations
Real-World Examples
HTTP API Calls
local function fetchUserData(userId)
PixelUI.runAsync(function()
loadingSpinner:show()
local url = "https://api.example.com/users/" .. userId
local response = http.get(url)
if response then
local userData = textutils.unserializeJSON(response.readAll())
response.close()
-- Update UI on main thread
userNameLabel:setText(userData.name)
userEmailLabel:setText(userData.email)
else
PixelUI.showToast("Failed to fetch user data", "Error", "error")
end
loadingSpinner:hide()
end, "fetchUser")
end
File Processing
local function processLargeFile(filename)
PixelUI.spawnThread(function()
local file = fs.open(filename, "r")
if not file then return end
local lineCount = 0
local progressBar = PixelUI.progressBar({x=10, y=10, width=20})
while true do
local line = file.readLine()
if not line then break end
lineCount = lineCount + 1
-- Process the line here
processLine(line)
-- Update progress every 100 lines
if lineCount % 100 == 0 then
progressBar:setProgress(lineCount / estimatedTotalLines)
PixelUI.sleep(0.01) -- Yield to keep UI responsive
end
end
file.close()
PixelUI.showToast("Processed " .. lineCount .. " lines", "Complete", "success")
end, "fileProcessor")
end
Background Monitoring
local function startSystemMonitor()
PixelUI.spawnThread(function()
while true do
-- Check system stats
local freeSpace = fs.getFreeSpace("/")
local energy = turtle and turtle.getFuelLevel() or 0
-- Update UI indicators
diskSpaceLabel:setText("Free: " .. freeSpace .. " bytes")
if turtle then
fuelLabel:setText("Fuel: " .. energy)
end
-- Check every 5 seconds
PixelUI.sleep(5)
end
end, "systemMonitor")
end
Best Practices
- Always Yield: Call
PixelUI.sleep()in loops to prevent blocking the UI - Handle Errors: Use
PixelUI.runAsync()for automatic error handling - Clean Resources: Close files, HTTP responses, and peripherals properly
- Update UI Safely: All UI updates should happen on the main thread
- Use Meaningful Names: Name your threads for easier debugging
- Monitor Long Tasks: Show progress indicators for lengthy operations
Thread Lifecycle
- Creation: Thread is created with
spawnThread()orrunAsync() - Execution: Thread runs cooperatively, yielding with
sleep() - Completion: Thread ends naturally or via
killThread() - Cleanup: Thread is automatically removed from the thread manager
The thread system integrates seamlessly with PixelUI's main event loop, ensuring your UI remains responsive while background tasks run efficiently.
๐งฉ Custom Widgets (Advanced)
Inherit from PixelUI.Widget:
local MyWidget = PixelUI.Widget:extend()
function MyWidget:render() ... end
function MyWidget:onClick(x, y, button) ... end
Register with PixelUI.registerWidget("myWidget", MyWidget) to use as PixelUI.myWidget().
๐งโ๐ป Advanced Usage
- Custom Widgets: Inherit from
PixelUI.Widgetand implement:render()and event handlers. - Direct Widget Access: All widget classes are available as
PixelUI.Label,PixelUI.Button, etc. - Manual Event Loop: Use
PixelUI.handleEvent(event, ...)for custom event processing. - Root Container: Use
PixelUI.setRootContainer(container)to replace the default root.
๐ Demo
Run example.lua for a full interactive demo of every widget and feature. Study the code for real-world usage patterns and advanced tricks.
โ FAQ
- Q: Can I use PixelUI in my own programs?
A: Yes! Just requirepixelui.luaand start building UIs. - Q: Is it fast?
A: Yes, it's optimized for CC: Tweaked and supports hundreds of widgets. - Q: Can I theme it?
A: Yes, see the theming section above. - Q: How do I add my own widgets?
A: Inherit fromPixelUI.Widgetand register your widget.
๐ License
MIT License. Use freely in your own projects, mods, and servers.
๐ฌ Support & Contributions
- Issues, suggestions, and PRs are welcome!
- For help, open an issue or ask in the CC: Tweaked Discord.
Enjoy building beautiful UIs in ComputerCraft with PixelUI!
Credits
DeepWiki and its badge was created by FLESHPRIS0N.