Engine events

Events the engine fires into hook. Subscribe with hook.Add.

event"OnVideoResized" → your callback receives (w, h)

The incoming video changed size — a different capture mode, a different console output setting, a stream restart. Fired before the first frame of the new size reaches OnFrameReceived, so anything you measured against the old frames can be thrown out in time. Note this is about the video, not the app window: resizing the window never moves a pixel of frame space, so there is deliberately no event for it.

event"KeyPress" → your callback receives (key)

Fired on key-down, whatever the overlay is doing. Whether an open menu should silence your keybind is your call, not the engine's: check OVERLAY_OPEN and return early if that is what you want.

The one thing the engine does decide: a focused textbox takes the keystroke first, and no KeyPress follows. Typing is never a keybind — a letter going into a pinned note must not also fire out of somebody's sentence.

Callback argTypeNotes
keystringThe key's display name, e.g. "P", "Space", "F1".

Return true to consume the key. A consumed key goes no further: later mods' "KeyPress" hooks do not fire for it, and neither do the app's own defaults (Escape closing the overlay — or, with the overlay closed, quitting the program). This is how a mod-drawn text field takes typing safely: its letters stop doubling as other mods' keybinds, and Escape lets go of the field instead of closing the app. Return nothing for keys that are not yours — consuming everything would eat every other mod's binds and the app's own controls.

The usual shape is to ignore keys while the menu is up — one line, and now it is a line you can see rather than a rule you cannot reach. The exceptions are the keys that are about what is on screen: a screenshot key that goes quiet with the overlay open cannot take the one picture it exists for.
hook.Add("KeyPress", "screenshotter", function(key)
    if OVERLAY_OPEN then return end         -- not while the menu is up
    if key == "P" then screenshot("screenshots/" .. os.time() .. ".png") end
end)
event"OverlayElement" → your callback receives (el)

Fired once per element, every frame, just before it is drawn — for every element, native ones included. Mutate the passed element table to restyle, rename, hide (el.hidden = true), or re-mode anything on the overlay.

Callback argTypeNotes
elElement (table)The live Element being drawn. Its el.id tells you which one; mutating it takes effect this frame.
hook.Add("OverlayElement", "myskin", function(el)
    if el.id == "options" then el.button.label = "Settings" end
    if el.id == "close_overlay" then el.hidden = true end
end)
event"OnFrameReceived" → your callback receives (frame)

Fired for every captured video frame, before it is displayed. Mutate the frame's pixels in place (through the Frame object) to alter what's shown — no return value needed. Handlers run in turn; if one returns a non-nil value, the remaining handlers are skipped for that frame.

Callback argTypeNotes
frameFrameA read/write view of the raw pixel buffer. See Frame.
Performance: this fires ~60×/second and byte access crosses into C each call, so heavy per-pixel loops in Lua are costly. Touch as few bytes as you can, and check frame:format() — capture frames are usually NV12 (planar YUV), not RGBA.
hook.Add("OnFrameReceived", "dim-top", function(frame)
    local pitch = frame:pitch()
    for row = 0, 40 do                 -- NV12: Y plane is the first rows
        for col = 0, frame:width() - 1 do
            frame:setByte(row * pitch + col, 16)   -- Y=16 -> black band
        end
    end
end)
One page of the MCCP modding reference. Every section is its own document; search covers all of them.