README modelled on upstream with rendered screenshots/GIF, docs/TODO.txt, screenshot tooling, t_readme snippet test, ImGui.NewTextBuffer helpers

This commit is contained in:
4DBug
2026-10-08 17:15:54 -05:00
parent e051302b23
commit e0c2c2cf21
18 changed files with 805 additions and 1 deletions
+300
View File
@@ -0,0 +1,300 @@
-- Renders README screenshots headless: runs one SCENE (prepended by tools/screenshots/make.py), composites the
-- backend's tile ImageLabels exactly like Roblox stacks them (ZIndex, nested offsets, ClipsDescendants) over a
-- background colour, and prints frames as "PX <frame> <y> <hex rgb row>" for the crop rect.
local G = require(game:GetService("ReplicatedStorage"):WaitForChild("ImGui"))
local ImGui, ImVec2, ImVec4 = G.ImGui, G.ImVec2, G.ImVec4
local Cond = G.ImGuiCond
ImGui.CreateContext()
local io = ImGui.GetIO()
io.ConfigFlags = bit32.bor(io.ConfigFlags, G.ImGuiConfigFlags.DockingEnable)
io.IniFilename = nil
G.ImGui_ImplRoblox.Init()
G.ImGui_ImplRoblox.SetRenderRate(0)
local BG = { 115, 140, 153 } -- examples/example_roblox clear_color
-- force tree nodes / headers / tabs open by label
local OPEN = {}
for _, fname in ipairs({ "TreeNode", "CollapsingHeader" }) do
local real = ImGui[fname]
ImGui[fname] = function(label, ...)
if OPEN[label] then ImGui.SetNextItemOpen(true, Cond.Always) end
return real(label, ...)
end
end
local SELECT_TAB = nil
local realBTI = ImGui.BeginTabItem
ImGui.BeginTabItem = function(label, p_open, flags)
if label == SELECT_TAB then flags = bit32.bor(flags or 0, G.ImGuiTabItemFlags.SetSelected) end
return realBTI(label, p_open, flags)
end
-- the demo sets its own pos/size (FirstUseEver) right before Begin: override it there
local DEMO_RECT = nil
local realBegin = ImGui.Begin
ImGui.Begin = function(name, ...)
if name == "Dear ImGui Demo" and DEMO_RECT then
ImGui.SetNextWindowPos(ImVec2(DEMO_RECT[1], DEMO_RECT[2]), Cond.Always); ImGui.SetNextWindowSize(ImVec2(DEMO_RECT[3], DEMO_RECT[4]), Cond.Always)
end
return realBegin(name, ...)
end
local function Pos(x, y, w, h) ImGui.SetNextWindowPos(ImVec2(x, y), Cond.Always); if w then ImGui.SetNextWindowSize(ImVec2(w, h), Cond.Always) end end
-- ---------------------------------------------------------------- scenes
-- Each: crop {x, y, w, h}, frames to capture (list), mouse position, draw(frame)
local scenes = {}
-- README "Usage" example, verbatim
local f, counter = 0.6, 0
local buf = ImGui.NewTextBuffer("Hello, world!", 256)
local my_color = ImVec4(1.0, 0.4, 0.2, 1.0)
local function HelloWorld()
ImGui.Begin("My First Tool")
ImGui.Text("Hello, world %d", 123)
if ImGui.Button("Save") then counter += 1 end
ImGui.InputText("string", buf, 256)
f = ImGui.SliderFloat("float", f, 0.0, 1.0)
ImGui.ColorEdit4("Color", my_color)
ImGui.End()
end
scenes.hello = { crop = { 0, 0, 420, 200 }, shots = { 30 }, mouse = { 1900, 1060 }, draw = function()
Pos(10, 10, 400, 180); HelloWorld()
end }
scenes.demo = { crop = { 0, 0, 1000, 740 }, shots = { 40 }, mouse = { 640, 330 }, draw = function()
OPEN["Widgets"] = true; OPEN["Basic"] = true
Pos(10, 10, 380, 200)
ImGui.Begin("Hello, world!")
ImGui.Text("This is some useful text.")
ImGui.Checkbox("Demo Window", true)
ImGui.SliderFloat("float", 0.42, 0.0, 1.0)
ImGui.Button("Button"); ImGui.SameLine(); ImGui.Text("counter = %d", 3)
ImGui.Text("Application average %.3f ms/frame (%.1f FPS)", 16.667, 60.0)
ImGui.End()
DEMO_RECT = { 410, 10, 580, 720 }; ImGui.ShowDemoWindow()
end }
scenes.tables = { crop = { 0, 0, 700, 740 }, shots = { 40 }, mouse = { 1900, 1060 }, draw = function()
OPEN["Tables & Columns"] = true; OPEN["Borders, background"] = true; OPEN["Sorting"] = true
DEMO_RECT = { 10, 10, 680, 720 }; ImGui.ShowDemoWindow()
end }
scenes.style = { crop = { 0, 0, 560, 740 }, shots = { 40 }, mouse = { 1900, 1060 }, draw = function()
SELECT_TAB = "Colors"
Pos(10, 10, 540, 720); ImGui.Begin("Dear ImGui Style Editor"); ImGui.ShowStyleEditor(); ImGui.End()
end }
scenes.metrics = { crop = { 0, 0, 620, 560 }, shots = { 40 }, mouse = { 1900, 1060 }, draw = function()
OPEN["Windows"] = true; OPEN["DrawLists"] = true
Pos(10, 10, 600, 540); ImGui.ShowMetricsWindow()
end }
scenes.docking = { crop = { 0, 0, 1100, 640 }, shots = { 40 }, mouse = { 1900, 1060 }, draw = function(frame)
Pos(10, 10, 1080, 620)
ImGui.Begin("Editor", nil, G.ImGuiWindowFlags.MenuBar)
if ImGui.BeginMenuBar() then
if ImGui.BeginMenu("File") then ImGui.EndMenu() end
if ImGui.BeginMenu("View") then ImGui.EndMenu() end
ImGui.EndMenuBar()
end
local id = ImGui.GetID("MainDock")
if frame == 2 then
ImGui.DockBuilderRemoveNode(id)
ImGui.DockBuilderAddNode(id, G.ImGuiDockNodeFlags.None)
ImGui.DockBuilderSetNodeSize(id, ImVec2(1064, 560))
local left, right = ImGui.DockBuilderSplitNode(id, G.ImGuiDir.Left, 0.3)
local rtop, rbottom = ImGui.DockBuilderSplitNode(right, G.ImGuiDir.Up, 0.65)
ImGui.DockBuilderDockWindow("Scene", left)
ImGui.DockBuilderDockWindow("Inspector", rtop)
ImGui.DockBuilderDockWindow("Properties", rtop)
ImGui.DockBuilderDockWindow("Console", rbottom)
ImGui.DockBuilderFinish(id)
end
ImGui.DockSpace(id)
ImGui.End()
ImGui.Begin("Scene")
for _, n in ipairs({ "Workspace", "Lighting", "Players", "ReplicatedStorage" }) do
if ImGui.TreeNode(n) then ImGui.BulletText("Part"); ImGui.BulletText("Model"); ImGui.TreePop() end
end
ImGui.End()
ImGui.Begin("Inspector")
ImGui.SeparatorText("Transform")
ImGui.DragFloat3("Position", { 12.0, 4.5, -3.0 }, 0.1)
ImGui.DragFloat3("Rotation", { 0.0, 90.0, 0.0 }, 1.0)
ImGui.SeparatorText("Appearance")
ImGui.ColorEdit3("Color", ImVec4(0.2, 0.6, 1.0, 1.0))
ImGui.SliderFloat("Transparency", 0.25, 0.0, 1.0)
ImGui.Checkbox("Anchored", true); ImGui.SameLine(); ImGui.Checkbox("CanCollide", false)
ImGui.End()
ImGui.Begin("Properties"); ImGui.Text("Properties"); ImGui.End()
ImGui.Begin("Console")
for i = 1, 6 do ImGui.TextColored(ImVec4(0.6, 0.9, 0.6, 1), "[%02d:00] Loaded chunk %d", i, i * 7) end
ImGui.End()
end }
-- README plot example (animated -> GIF)
local values, hist = {}, { 0.6, 0.1, 1.0, 0.5, 0.92, 0.1, 0.2 }
scenes.plot = { crop = { 0, 0, 440, 330 }, shots = {}, mouse = { 1900, 1060 }, draw = function(frame)
local t = frame / 30
for i = 1, 90 do values[i] = math.sin((i / 90) * math.pi * 4 + t * 3) * math.cos(t + i * 0.05) end
for i = 1, #hist do hist[i] = 0.5 + 0.5 * math.sin(t * 2 + i) end
Pos(10, 10, 420, 310)
ImGui.Begin("Plotting")
ImGui.PlotLines("Lines", values, nil, #values, 0, "sine", -1.0, 1.0, ImVec2(0, 90))
ImGui.PlotHistogram("Histogram", hist, nil, #hist, 0, nil, 0.0, 1.0, ImVec2(0, 90))
ImGui.ProgressBar((t * 0.4) % 1.0, ImVec2(-1, 0))
ImGui.Text("frame %d", frame)
ImGui.End()
end }
for i = 30, 149 do table.insert(scenes.plot.shots, i) end
scenes.drawlist = { crop = { 0, 0, 380, 300 }, shots = { 30 }, mouse = { 1900, 1060 }, draw = function()
Pos(10, 10, 360, 280)
ImGui.Begin("Custom drawing")
local dl = ImGui.GetWindowDrawList()
local p = ImGui.GetCursorScreenPos()
dl:AddRectFilled(p, p + ImVec2(100, 100), G.IM_COL32(255, 120, 60, 255), 12.0)
dl:AddCircleFilled(p + ImVec2(170, 50), 45, G.IM_COL32(80, 160, 255, 255))
dl:AddTriangleFilled(p + ImVec2(230, 100), p + ImVec2(280, 0), p + ImVec2(330, 100), G.IM_COL32(120, 220, 120, 255))
dl:AddBezierCubic(p + ImVec2(0, 140), p + ImVec2(100, 100), p + ImVec2(200, 220), p + ImVec2(330, 150), G.IM_COL32(255, 255, 0, 255), 3.0)
dl:AddText(p + ImVec2(0, 190), G.IM_COL32(255, 255, 255, 255), "ImDrawList: lines, shapes, text")
ImGui.Dummy(ImVec2(330, 220))
ImGui.End()
end }
-- README hero: same "Debug" window in the dark and light styles (like upstream's README)
local dbg_buf = ImGui.NewTextBuffer("quick brown fox", 256)
local function DebugWindow(title)
ImGui.Begin(title)
ImGui.Text("Hello, world %d", 123)
ImGui.Button("Save")
ImGui.InputText("string", dbg_buf, 256)
ImGui.SliderFloat("float", 0.6, 0.0, 1.0)
ImGui.End()
end
scenes.debug = { crop = { 0, 0, 540, 150 }, shots = { 30 }, mouse = { 140, 113 }, cursor = true, draw = function()
Pos(10, 10, 250, 130); DebugWindow("Debug##dark")
local saved = {}
for i, c in pairs(ImGui.GetStyle().Colors) do saved[i] = ImVec4(c.x, c.y, c.z, c.w) end
ImGui.StyleColorsLight()
Pos(280, 10, 250, 130); DebugWindow("Debug##light")
for i, c in pairs(saved) do G.ImVec4_Copy(ImGui.GetStyle().Colors[i], c) end
end }
-- README "My First Tool" (verbatim from README.md / t_readme.luau), with the color picker popup opened by a click
local my_tool_active, tool_color = true, ImVec4(0.455, 0.282, 0.455, 1.0)
local samples = {}
local btn = nil
scenes.tool = { crop = { 0, 0, 560, 420 }, shots = { 40 }, cursor = true,
mouse = function(frame) if frame < 16 then return btn and btn[1] or 5, btn and btn[2] or 5 end return 300, 240 end,
button = function(frame) if frame == 12 then return true elseif frame == 13 then return false end end,
draw = function()
io.ConfigColorEditFlags = bit32.bor(G.ImGuiColorEditFlags.PickerHueWheel, G.ImGuiColorEditFlags.Uint8, G.ImGuiColorEditFlags.DisplayRGB, G.ImGuiColorEditFlags.InputRGB)
Pos(10, 10, 340, 330)
-- [snippet:tool]
-- Create a window called "My First Tool", with a menu bar.
my_tool_active = ImGui.Begin("My First Tool", my_tool_active, G.ImGuiWindowFlags.MenuBar)
if ImGui.BeginMenuBar() then
if ImGui.BeginMenu("File") then
if ImGui.MenuItem("Open..", "Ctrl+O") then --[[ Do stuff ]] end
if ImGui.MenuItem("Save", "Ctrl+S") then --[[ Do stuff ]] end
if ImGui.MenuItem("Close", "Ctrl+W") then my_tool_active = false end
ImGui.EndMenu()
end
ImGui.EndMenuBar()
end
-- Edit a color stored as 4 floats
local p, w, h = ImGui.GetCursorScreenPos(), ImGui.CalcItemWidth(), ImGui.GetFrameHeight()
btn = { p.x + w - h * 0.5, p.y + h * 0.5 }
ImGui.ColorEdit4("Color", tool_color)
-- Generate samples and plot them
for n = 1, 100 do samples[n] = math.sin((n - 1) * 0.2 + ImGui.GetTime() * 1.5) end
ImGui.PlotLines("Samples", samples, nil, 100)
-- Display contents in a scrolling region
ImGui.TextColored(ImVec4(1, 1, 0, 1), "Important Stuff")
ImGui.BeginChild("Scrolling")
for n = 0, 49 do ImGui.Text("%04d: Some text", n) end
ImGui.EndChild()
ImGui.End()
-- [/snippet]
end }
local SC = assert(scenes[SCENE], "unknown SCENE")
io.MouseDrawCursor = SC.cursor == true
-- ---------------------------------------------------------------- compositor
local CX, CY, CW, CH = SC.crop[1], SC.crop[2], SC.crop[3], SC.crop[4]
local function composite(gui)
local screen = buffer.create(CW * CH * 3)
for i = 0, CW * CH - 1 do buffer.writeu8(screen, i * 3, BG[1]); buffer.writeu8(screen, i * 3 + 1, BG[2]); buffer.writeu8(screen, i * 3 + 2, BG[3]) end
local function walk(inst, ox, oy, kx0, ky0, kx1, ky1)
local kids = inst:GetChildren()
table.sort(kids, function(a, b) return (a.ZIndex or 1) < (b.ZIndex or 1) end)
for _, c in ipairs(kids) do
if c.Visible ~= false then
local x, y = ox + (c.Position and c.Position.X or 0), oy + (c.Position and c.Position.Y or 0)
local cx0, cy0, cx1, cy1 = kx0, ky0, kx1, ky1
if c.ClipsDescendants then
cx0, cy0 = math.max(cx0, x), math.max(cy0, y)
cx1, cy1 = math.min(cx1, x + c.Size.X), math.min(cy1, y + c.Size.Y)
end
if c.ClassName == "ImageLabel" then
local img = c.ImageContent.Object
local px, sz = img.Pixels, img.Size.X
for ty = 0, sz - 1 do
local sy = y + ty
if sy >= ky0 and sy < ky1 then
for tx = 0, sz - 1 do
local sx = x + tx
if sx >= kx0 and sx < kx1 then
local o = (ty * sz + tx) * 4
local a = buffer.readu8(px, o + 3)
if a > 0 then
local d = ((sy - CY) * CW + (sx - CX)) * 3
local fa = a / 255
for ch = 0, 2 do
local v = buffer.readu8(px, o + ch) * fa + buffer.readu8(screen, d + ch) * (1 - fa)
buffer.writeu8(screen, d + ch, math.floor(v + 0.5))
end
end
end
end
end
end
end
walk(c, x, y, cx0, cy0, cx1, cy1)
end
end
end
walk(gui, 0, 0, CX, CY, CX + CW, CY + CH)
return screen
end
local shoot = {}
for _, s in ipairs(SC.shots) do shoot[s] = true end
local frame = 0
game:GetService("RunService").Stepped:Connect(function()
frame += 1
G.ImGui_ImplRoblox.NewFrame()
io.DeltaTime = 1 / 30
if type(SC.mouse) == "function" then io:AddMousePosEvent(SC.mouse(frame)) else io:AddMousePosEvent(SC.mouse[1], SC.mouse[2]) end
local b = SC.button and SC.button(frame)
if b ~= nil then io:AddMouseButtonEvent(0, b) end
ImGui.NewFrame()
SC.draw(frame)
ImGui.Render()
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
if shoot[frame] then
local screen = composite(game:GetService("Players").LocalPlayer.PlayerGui:FindFirstChild("ImGui"))
print("SIZE", CW, CH)
for y = 0, CH - 1 do
local t = table.create(CW * 3)
for i = 0, CW * 3 - 1 do t[i + 1] = string.format("%02x", buffer.readu8(screen, y * CW * 3 + i)) end
print("PX", frame, y, table.concat(t))
end
end
end)
+42
View File
@@ -0,0 +1,42 @@
#!/usr/bin/env python3
# Renders README images into docs/images/: python3 tools/screenshots/make.py [scene ...]
# Stills -> PNG (zlib, stdlib only); the "plot" scene -> GIF via ffmpeg (palette).
import os, struct, subprocess, sys, tempfile, zlib
ROOT = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
OUT = os.path.join(ROOT, "docs", "images")
STILLS = ["debug", "tool", "hello", "demo", "tables", "style", "metrics", "docking", "drawlist"]
def png(path, w, h, rows):
raw = b"".join(b"\x00" + r for r in rows)
def chunk(t, d): return struct.pack(">I", len(d)) + t + d + struct.pack(">I", zlib.crc32(t + d) & 0xffffffff)
open(path, "wb").write(b"\x89PNG\r\n\x1a\n" + chunk(b"IHDR", struct.pack(">IIBBBBB", w, h, 8, 2, 0, 0, 0))
+ chunk(b"IDAT", zlib.compress(raw, 9)) + chunk(b"IEND", b""))
def run(scene):
src = open(os.path.join(ROOT, "tools", "screenshots", "capture.luau")).read()
tmp = os.path.join(tempfile.mkdtemp(), "scene.luau")
open(tmp, "w").write('SCENE = "%s"\n' % scene + src)
frames = 152 if scene == "plot" else 42
p = subprocess.run([sys.executable, os.path.join(ROOT, "tools", "test", "run.py"), "--main", tmp, "--frames", str(frames),
"--quiet", "--roblox", "--timeout", "1200"], capture_output=True, text=True, env=dict(os.environ, FULL_OUTPUT="1"))
shots, size = {}, None
for l in p.stdout.splitlines():
if l.startswith("SIZE"): size = tuple(map(int, l.split()[1:]))
elif l.startswith("PX"):
_, f, y, hx = l.split(); shots.setdefault(int(f), {})[int(y)] = bytes.fromhex(hx)
if not shots: sys.exit("scene %s failed:\n%s" % (scene, p.stdout[-3000:]))
w, h = size
return w, h, [[rows[y] for y in range(h)] for _, rows in sorted(shots.items())]
os.makedirs(OUT, exist_ok=True)
for scene in sys.argv[1:] or STILLS + ["plot"]:
w, h, frames = run(scene)
if scene == "plot":
d = tempfile.mkdtemp()
for i, rows in enumerate(frames): png(os.path.join(d, "f%04d.png" % i), w, h, rows)
subprocess.run(["ffmpeg", "-loglevel", "error", "-y", "-framerate", "30", "-i", os.path.join(d, "f%04d.png"), "-vf",
"split[a][b];[a]palettegen=stats_mode=diff[p];[b][p]paletteuse=dither=none", "-loop", "0",
os.path.join(OUT, "plot.gif")], check=True)
else:
png(os.path.join(OUT, scene + ".png"), w, h, frames[-1])
print("wrote", scene)
+139
View File
@@ -0,0 +1,139 @@
-- Every code snippet in README.md, verbatim between the "-- [snippet]" markers. Must print README OK.
local ReplicatedStorage = game:GetService("ReplicatedStorage")
local RunService = game:GetService("RunService")
local G = require(ReplicatedStorage:WaitForChild("ImGui"))
local ImGui, ImVec2, ImVec4 = G.ImGui, G.ImVec2, G.ImVec4
ImGui.CreateContext()
G.ImGui_ImplRoblox.Init()
-- [snippet:hello]
local f, counter = 0.6, 0
local buf = ImGui.NewTextBuffer("Hello, world!", 256) -- InputText edits a byte buffer in place
local my_color = ImVec4(1.0, 0.4, 0.2, 1.0)
local function MyFirstTool()
ImGui.Begin("My First Tool")
ImGui.Text("Hello, world %d", 123)
if ImGui.Button("Save") then
counter += 1
end
ImGui.InputText("string", buf, 256)
f = ImGui.SliderFloat("float", f, 0.0, 1.0)
ImGui.ColorEdit4("Color", my_color) -- ImVec4 arguments are edited in place
ImGui.End()
end
-- [/snippet]
-- [snippet:conventions]
local enabled, volume, mode = true, 50, 0
local function Conventions()
ImGui.Begin("Conventions")
local pressed
pressed, enabled = ImGui.Checkbox("Enabled", enabled) -- bool widgets: pressed, new value
local changed
volume, changed = ImGui.SliderInt("Volume", volume, 0, 100) -- scalar widgets: new value, changed
mode = ImGui.Combo("Mode", mode, { "Easy", "Normal", "Hard" }) -- Combo/ListBox: 0-based index
if pressed or changed then print("settings changed") end
ImGui.End()
end
-- [/snippet]
-- [snippet:menus]
local show_log = false
local function MenusAndTable()
ImGui.Begin("Inventory", nil, G.ImGuiWindowFlags.MenuBar)
if ImGui.BeginMenuBar() then
if ImGui.BeginMenu("View") then
_, show_log = ImGui.MenuItem("Show log", nil, show_log)
ImGui.EndMenu()
end
ImGui.EndMenuBar()
end
local flags = bit32.bor(G.ImGuiTableFlags.Borders, G.ImGuiTableFlags.RowBg)
if ImGui.BeginTable("items", 3, flags) then
ImGui.TableSetupColumn("Name")
ImGui.TableSetupColumn("Count")
ImGui.TableSetupColumn("Value")
ImGui.TableHeadersRow()
for _, item in ipairs({ { "Sword", 1, 120 }, { "Potion", 5, 15 }, { "Arrow", 64, 1 } }) do
ImGui.TableNextRow()
ImGui.TableNextColumn(); ImGui.Text(item[1])
ImGui.TableNextColumn(); ImGui.Text("%d", item[2])
ImGui.TableNextColumn(); ImGui.Text("%d", item[3])
end
ImGui.EndTable()
end
ImGui.End()
end
-- [/snippet]
-- [snippet:plot]
local samples = {}
local function Plot()
for i = 1, 90 do
samples[i] = math.sin(i / 90 * math.pi * 4 + os.clock() * 3)
end
ImGui.Begin("Plotting")
ImGui.PlotLines("Lines", samples, nil, #samples, 0, "sine", -1.0, 1.0, ImVec2(0, 80))
ImGui.ProgressBar((os.clock() * 0.4) % 1.0, ImVec2(-1, 0))
ImGui.End()
end
-- [/snippet]
-- [snippet:drawlist]
local function CustomDrawing()
ImGui.Begin("Custom drawing")
local draw_list = ImGui.GetWindowDrawList()
local p = ImGui.GetCursorScreenPos()
draw_list:AddRectFilled(p, p + ImVec2(100, 100), G.IM_COL32(255, 120, 60, 255), 12.0)
draw_list:AddCircleFilled(p + ImVec2(170, 50), 45, G.IM_COL32(80, 160, 255, 255))
draw_list:AddLine(p + ImVec2(0, 120), p + ImVec2(220, 120), G.IM_COL32(255, 255, 0, 255), 2.0)
ImGui.Dummy(ImVec2(220, 130)) -- reserve the space so the window sizes/scrolls correctly
ImGui.End()
end
-- [/snippet]
-- [snippet:tool]
local my_tool_active, my_color2, samples2 = true, ImVec4(0.45, 0.28, 0.45, 1.0), {}
local function MyTool()
-- Create a window called "My First Tool", with a menu bar.
my_tool_active = ImGui.Begin("My First Tool", my_tool_active, G.ImGuiWindowFlags.MenuBar)
if ImGui.BeginMenuBar() then
if ImGui.BeginMenu("File") then
if ImGui.MenuItem("Open..", "Ctrl+O") then --[[ Do stuff ]] end
if ImGui.MenuItem("Save", "Ctrl+S") then --[[ Do stuff ]] end
if ImGui.MenuItem("Close", "Ctrl+W") then my_tool_active = false end
ImGui.EndMenu()
end
ImGui.EndMenuBar()
end
-- Edit a color stored as 4 floats
ImGui.ColorEdit4("Color", my_color2)
-- Generate samples and plot them
for n = 1, 100 do samples2[n] = math.sin((n - 1) * 0.2 + ImGui.GetTime() * 1.5) end
ImGui.PlotLines("Samples", samples2, nil, 100)
-- Display contents in a scrolling region
ImGui.TextColored(ImVec4(1, 1, 0, 1), "Important Stuff")
ImGui.BeginChild("Scrolling")
for n = 0, 49 do ImGui.Text("%04d: Some text", n) end
ImGui.EndChild()
ImGui.End()
end
-- [/snippet]
local frame = 0
RunService.Stepped:Connect(function()
frame += 1
G.ImGui_ImplRoblox.NewFrame()
ImGui.NewFrame()
MyFirstTool(); MyTool(); Conventions(); MenusAndTable(); Plot(); CustomDrawing()
ImGui.Render()
G.ImGui_ImplRoblox.RenderDrawData(ImGui.GetDrawData())
if frame == 20 then
assert(ImGui.TextBufferToString(buf) == "Hello, world!")
print("README OK")
end
end)