No permission needed.
panorama.ready is false while the UI engine isn’t found; lookups return
null and lists come back empty until it is.Overview
Finding panels
ref, find, path, findAll, walk, windows, the inspector.Panels
Panel and UIWindow: tree, visibility, opacity, text, classes, screen position.What's painted
drawList, panelsAt, paintOps, DrawItem, PaintOp.Coverage
coverageShapes, coverage, isCovered: keep your drawing off the HUD.Finding panels
find, path, findAll and ref take { in, visibleOnly }: in limits the search to a panel’s
subtree or one window, visibleOnly skips hidden subtrees (a lot cheaper on the menu, where most pages
are hidden). walk takes { maxDepth, visibleOnly, paintOrder }.
Layer names the windows: hud ("CSGOHud"), mainMenu, loadingScreen, popups, customHuds,
console.
ref
PanelRef finds it again: get() returns the panel, or null while there isn’t one. A miss is
retried at most every retryMs (default 500), so calling get() every frame is fine.
Finding an id
Hover the thing you want:F8 toggles it, PageUp / PageDown walk through the panels stacked under the cursor. It shows the
path, class, bounds, opacity, classes and text. Options: toggleKey, enabled (default true),
intervalMs (hit-test interval, default 100). It returns { enabled, hovered, dispose() }.
Or print the tree:
dump positions are in window pixels. panorama.draw(panel, options?) outlines one panel where it’s
drawn, inside render only: color (magenta), fill, label (true for id [Type] WxH, a string,
or false), thickness.
Panels
APanel is one panorama panel. You get the same object for the same panel while you hold it.
Bounds are
{ x, y, width, height, min, max }, so min/max go straight into render.rect. Quads
are top-left, top-right, bottom-right, bottom-left. The position methods return null for a panel
that’s gone.
A UIWindow is one top-level layer: HUD, main menu, loading screen, popups, console. It has name
(its root’s id), root, roots (in paint order), shown (the main menu isn’t, in a match), width,
height, size, scale (height / 1080), find(id), toScreenScale(), address and alive.
What’s painted
drawList takes { in, contentOnly, minOpacity }, panelsAt / panelAt the same plus skip(panel).
contentOnly drops layout containers, minOpacity defaults to 0.01.
A
PaintOp is one thing panorama drew: a fill, gradient, image, text run, blur, border or shadow.
paintOps takes { in, minAlpha, kinds, skip(op) }, minAlpha defaulting to 0.02.
Read an op’s geometry in the frame you got it. It’s kept for a few frames, then it’s gone.
Coverage
Where panorama actually paints, built from every primitive above. This is the mask to keep your drawing off the HUD, the menu and the scoreboard.
Both shape calls take the
paintOps options. isCovered takes { in, minAlpha, skip(panel) }.
Icons and opacity-mask images are cut to their real pixels, so a weapon silhouette or a round avatar
covers just its shape. The images load in the background; until one has, it counts as a full rectangle.
panorama.imageAlpha = false turns this off and every image is a rectangle.
Draw order
The same order panorama paints in:- Windows in
windows()order: HUD, then main menu, loading screen, popups, console. - The window’s roots, in order.
- Depth-first: a parent, then its children sorted by
z-index(ties keep children order).z-indexonly sorts siblings.
CSGOHud; the main menu’s popups are their own
window. The scoreboard is Scoreboard in the HUD and stays empty (0×0) until it’s opened. All of it
lands in drawList and the coverage as soon as it’s painted.
Styles that count
Limitations
- Text covers its line box, not the glyphs.
- Only what panorama draws. The engine’s own overlays and console text (the radio and chat lines in the corner) aren’t in it.
- During a transition or animation, opacity and transforms read as their end values. Only position is
interpolated.
animatingtells you when it’s happening. perspectiveis applied without the perspective divide.- Color filters (
wash-color,brightness,saturation,hue-rotation,mix-blend-mode) are ignored. Borders follow the panel’s edge. background-imageon non-image panels and Steam avatars stay rectangles.
Tools
Nothing is read until you ask. After the first frame only what panorama changed gets read again, so
calling
coverageShapes every frame is fine.