Quick navigation

Go to

WebUI & HUD

Vanilla HUD visibility

Show and hide native HUD components, or mask the HUD, watermark and nonfocused resource interfaces with cinematic letterbox bars. Resource-owned claims, cleanup and native notifications.

6 min read1,403 wordsMarkdown
On this page9 sections

Use Open77.hud to hide selected native HUD modules and replace them with resource-owned interfaces. Client resources require ui.vanilla.hud:

permissions { "ui.vanilla.hud" }

This is a client-only presentation API. It does not grant a server resource direct access to a player's HUD; a server gamemode should send an event to its client resource and let that resource own the visibility claim.

Cinematic display

For a clean cinematic view including resource WebUIs, watermark, world labels and letterbox bars, use Open77.hud.setCinematic(true[, height]), then Open77.hud.setCinematic(false) to release your resource's claim. This requires the same ui.vanilla.hud permission. See cinematic display for ranges, ownership, cleanup and the deliberate focused-menu exception. Freeroam exposes this as /cinematic [on|off].

Multiplayer defaults

During an authenticated Open77 session, the platform automatically removes solo-game input hints, the phone/radio/quick-slot cluster, and the lower-right standing/crouching silhouette. Those fixed multiplayer restrictions are separate from Open77.hud and are restored when the multiplayer policy ends.

Open77.hud controls the remaining optional modules that a resource may replace with its own UI.

Three of those fixed restrictions overlap with a component name β€” the quick-slot cluster is hubMenu, the phone row is phone, and the scanner is scanner. During a multiplayer session the platform hides all three whether or not a resource claims them, and releasing your claim will not bring them back until the session ends. Outside multiplayer, the claim is the only thing hiding them.

state() and isVisible() report claims, not what is on screen: they answer "does any resource hide this", and they do not know about the multiplayer policy. A component can therefore read true while the session keeps it off the screen.

Components

Component Vanilla UI controlled
minimap Map panel, geometry, player marker, mappins, GPS lines, frame and location label
compass Compass strip in the top-right map area
clock Time display above the minimap
health Player health, armor, memory and attached buff bar
stamina Player stamina bar
weapon Complete active-weapon presentation: loaded/reserve ammunition, weapon icon, and legacy charge/trigger indicator
speedometer Digital and analog vehicle speed displays
questTracker The tracked-objective panel and its yellow GPS route
phone The standalone phone/messages HUD row
scanner The scan overlay and scanner activation β€” see the note below
vanillaNotifications Cyberpunk's own side-popup notification stack
crosshair Every weapon crosshair, including the melee and cyberware variants
hubMenu The bottom-left quick-slot / D-pad hub cluster

Component names are matched case-insensitively, so questTracker and questtracker are the same component. These aliases are also accepted by setVisible and isVisible:

Alias Component
map, radar minimap
time clock
hp health
ammo, weapons, weaponAmmo weapon
speed speedometer
quest, tracker, objectives questTracker
vision, visionMode scanner
notifications, notification, toasts vanillaNotifications
reticle, reticule crosshair
hub hubMenu

Snapshots always use the canonical names above.

all

all is a selector, not a component: it claims or releases every component at once for the calling resource. It never appears in components() or in a state() snapshot, because there is no widget called "all".

Open77.hud.setVisible("all", false)   -- this resource now hides every component
Open77.hud.setVisible("all", true)    -- and releases every claim it holds

isVisible("all") answers true only when every component is visible. A false there means at least one component is hidden by someone β€” not necessarily by you.

Two components that do more than hide a widget

scanner is the one claim that also refuses an input. Hiding only the overlay would leave an invisible scanner still holding aim snap and the movement restriction β€” a player walking slowly with no UI explaining why. So the claim hides the scan overlay and refuses scanner activation, exactly as the multiplayer policy does. If you want to refuse the input without hiding anything, use the Scanner entry of Open77.actions instead.

vanillaNotifications is the same stack Open77.hud.notify writes to. A resource that hides this component is hiding its own vanilla toasts too.

API

local ok, effectiveOrReason = Open77.hud.setVisible(component, visible)
local visible, reason = Open77.hud.isVisible(component)
local state, reason = Open77.hud.state()
local components, reason = Open77.hud.components()

setVisible(component, false) adds a hide claim owned by the calling resource. Passing true releases that resource's claim; it does not override another resource that still hides the same component. On success, the second result is the effective visibility after all claims are combined.

Every claim is released automatically when the owning resource stops or reloads. Static widgets restore the state observed before the first hide; contextual health and stamina widgets ask their vanilla controller to evaluate visibility again.

local ok, effective = Open77.hud.setVisible("health", false)
if not ok then
  error(effective)
end

-- Render the custom health WebUI here.

local state = assert(Open77.hud.state())
print(state.health) -- false

-- Optional: releasing explicitly avoids waiting for resource shutdown.
Open77.hud.setVisible("health", true)

Replace the complete supported HUD

Use components() instead of copying the component list into a resource. This automatically picks up future supported components:

local hidden = assert(Open77.hud.components())

for _, component in ipairs(hidden) do
    local ok, effectiveOrReason = Open77.hud.setVisible(component, false)
    assert(ok, effectiveOrReason)
end

-- Create and update the custom WebUI here.

local function restoreVanillaHud()
    for _, component in ipairs(hidden) do
        Open77.hud.setVisible(component, true)
    end
end

Explicit restoration is useful during a gamemode transition. Resource stop and reload remain the final safety net, so a crashed UI resource cannot leave its claims behind.

Multiple resources

Visibility is combined as an AND policy: a component is visible only when no resource currently hides it. For example, if both a racing HUD and a cinematic resource hide minimap, releasing the racing claim does not reveal the map until the cinematic resource releases its claim too.

local accepted, effective = Open77.hud.setVisible("minimap", true)
if accepted and not effective then
    print("another resource still hides the minimap")
end

The complete minimap component includes its geometry, player marker, mappins, GPS route, frame, and location label. Hide compass or clock independently when those elements should remain.

Vanilla toasts

The same table also writes to Cyberpunk's own notification pipelines. These look native in a way a web toast never will, and they cost nothing: no browser surface, no resource dependency.

Open77.hud.notify(text [, options])   -- vanilla side popup
Open77.hud.log(text)                  -- a line in the activity log
Open77.hud.menu(preset)               -- a vanilla menu notification
Open77.hud.clearNotify([channel])     -- "ingame" (default) or "menu"

They need the same ui.vanilla.hud permission as the visibility calls, return true on success, and false, reason on failure.

What works, and what does not

Call Pipeline Status on 2.31
notify(text) UIInGameNotificationEvent β€” the side popup Works. Confirmed on screen.
log(text) gameActivityLogSystem.AddLog Works. Confirmed on screen.
menu(preset) UIMenuNotificationEvent Works, but only while the menu layer that owns the queue is mounted.
help(text, ms) MPDisplayOnscreenMessage Unsupported. Refused with unsupported_channel.
subtitle(text, ms) MPDisplayNarrationEventEntry Unsupported. Refused with unsupported_channel.

help and subtitle are bound, validate their arguments, and then stop at the facade. They are not missing by omission: the globals behind them are Cyberpunk's dormant multiplayer (CPO) HUD, which assumes a context the single-player build never mounts. Calling MPDisplayOnscreenMessage closed the process with an access violation reading 0x0 (crash report Cyberpunk2077-20260804-173018-14844-21448), and the two neighbouring globals from the same group are not invoked on principle. The names stay bound so a resource written against them keeps working the day the channel is real; until then, use notify and expect false, "unsupported_channel" from the other two.

The in-game popup

notify queues a five-second side popup. The duration is the engine's and cannot be changed β€” that is why notify takes no ms argument while help does.

local ok, reason = Open77.hud.notify("BOUNTY CLAIMED")
if not ok then print(reason) end

-- Replace what is on screen instead of queueing behind it.
Open77.hud.notify("ARREST WARRANT", { replace = true })

-- A vanilla preset: the engine shows the preset's own localized title.
Open77.hud.notify(nil, { preset = "combat_blocked" })

A preset replaces your text. Called with "Refused: already_fixed" and the action_blocked preset, the popup showed only the localized "ACTION IMPOSSIBLE". To tell the player why, use the default generic preset, which draws your text in the same banner.

options.preset accepts generic (the default), action_blocked, combat_blocked, cant_save_action, cant_save_combat, cant_save_quest, cant_save_death, save_slots_full, save_space_full, photo_mode_disabled, sandevistan_in_call and expansion_installed.

menu(preset) accepts vendor_not_enough_money, not_enough_money, inventory_action_blocked, crafting_not_enough_materials, upgrade_level_too_low, no_perk_points, perks_locked, perks_max_level, no_attribute_points, in_combat, in_combat_explicit, crafting_quickhack, crafting_ammo_cap, player_level_too_low, inventory_full, face_unequip_blocked, tutorial_unequip_blocked and no_junk. A menu preset carries its own localized title, so it takes no text. Two vanilla presets are deliberately absent: one needs a real gameplay payload, the other renders no title at all on 2.31.

There is one vanilla slot per channel. clearNotify empties it whoever filled it, and hiding the vanillaNotifications component hides the whole stack β€” including your own toasts.

Which toast to reach for

You want Use
A toast that looks like the game's own Open77.hud.notify
A toast you control β€” colour, icon, duration, stacking, dismissal open77_notifications

Open77.hud.notify is free and native-looking but takes the engine's styling and its five seconds. open77_notifications is a WebUI service with its own definition format, updates and dismissal, at the cost of a resource dependency and a browser surface.

Refusals: permission_denied:ui.vanilla.hud, invalid_notification_text, invalid_notification_preset, invalid_notification_duration, invalid_notification_channel, options_must_be_a_table, unsupported_channel, plus the facade's own wrong_thread, world_unavailable, ui_system_unavailable, activity_log_unavailable and invocation_failed.

Debug commands

When the privileged open77_debug resource is loaded, an authorized player can test the policy without client execution:

/hud minimap hide
/hud crosshair hide
/hud all hide
/hud minimap show
/hud state
/hudtest hide
/hudtest show

Calls fail with permission_denied:ui.vanilla.hud, invalid_hud_arguments, invalid_hud_component, or hud_unavailable_on_this_host. This API is presentation-only: it does not modify health, stamina, ammunition, vehicle speed, or any replicated gameplay state.

Loading-screen integration

To hide the HUD only during a native load, see custom loading screens. The example owns and releases its HUD claims, keeps a WebUI cover ready, and closes it when native loading finishes.

// For agents & LLMsthis page as Markdownllms.txtllms-full.txt

// Guides Β· Lua API

Search the docs

1,905 guides and functions indexed

Try