Game-native UI screens
Compose screens inside the game's Scaleform movies with NativeUI, drive the game's own UI elements and turn off its menus from a client script.
NativeUI draws with the game’s own Scaleform renderer: your screen uses the
game’s fonts and artwork, sits in its layer stack and can be navigated with a
controller. You position every piece yourself. Use it when something should look
like part of KCD2, and a web view for everything else; a
resource can use both.
NativeUI.createScreengives an emptyNativeScreento composeNativeClips into.NativeUI.elementgives aNativeElement, a handle on one of the game’s existing screens.NativeUI.setMenuEnabledkeeps one of the game’s menus, such as the inventory or the map, from opening.
Build a first screen
Section titled “Build a first screen”const screen = NativeUI.createScreen();
screen.on("ready", () => { const root = screen.root; if (!root) return;
// A filled panel, drawn with the ActionScript drawing API. No assets needed. const panel = root.createClip(); if (!panel) return; panel.invoke("beginFill", [0x1a1109, 92]); panel.invoke("moveTo", [0, 0]); panel.invoke("lineTo", [840, 0]); panel.invoke("lineTo", [840, 300]); panel.invoke("lineTo", [0, 300]); panel.invoke("endFill"); panel.set({ x: 540, y: 390 });
const label = panel.createText({ x: 32, y: 28, width: 776, height: 244 }); label?.setTextStyle({ font: "DisplayFont", size: 34, color: 0xe7e0cf }); label?.setText("Kingdoms Connected");
panel.on("press", () => Hud.showNotification("clicked")); screen.focus();});
// The back action, while the screen holds focus.screen.on("input", (action: string) => { if (action === "kcdc_ui_back") { screen.blur(); screen.setVisible(false); }});Four rules that sample follows:
- Build in
ready. The movie loads a few frames aftercreateScreenreturns. Until thenscreen.readyis false,screen.rootis null and every call fails.readyalways arrives on a later tick. - Positions are stage units, not pixels. The stage is scaled to the
player’s resolution, so lay out at 1920 by 1080 like the game’s own movies.
screen.stage()reports the size;screen.screenToStage(x, y)turns a viewport fraction (0 to 1) into stage units. - Scale and alpha are multipliers in
set():scaleX: 1is natural size,alpha: 0.5half transparent. The rawclip.get("_xscale")reads 100. - Events arrive a tick late, so a handler cannot veto what raised it.
Add clips and text
Section titled “Add clips and text”Everything on a screen is a clip under screen.root:
| Call | Makes or does |
|---|---|
createClip() |
An empty child, for grouping or drawing into |
createText({ x, y, width, height, text?, html? }) |
A native text field |
attach(exportName) |
A sprite exported by the screen’s library |
set({ x, y, rotation, scaleX, scaleY, alpha, visible }) |
Moves, scales, fades, hides; only the fields present |
invoke(method, args) |
Calls an ActionScript method; the drawing API is beginFill, lineStyle, moveTo, lineTo, curveTo, endFill, clear |
setMember(name, value), get(name) |
Writes or reads one ActionScript property |
goto(frameOrLabel, play?) |
Moves the clip’s timeline |
setMask(clip), setHitArea(clip) |
Masks this clip, or gives it a different click shape |
load(url) |
Loads an img:// or imgps:// image, or a movie path in the game’s archives, into the clip |
remove() |
Takes it off the screen with its handlers |
Only numbers, strings, booleans and null cross into ActionScript; objects and
arrays do not.
Text draws in DefaultFont at size 20 unless restyled with setTextStyle.
Fonts are the game’s logical names, which keeps them right in every language:
| Name | Face |
|---|---|
DefaultFont, DefaultFontBold, DefaultFontItalic |
Kingdom Come Regular |
LightFont, LightFontBold, LightFontItalic |
Kingdom Light Regular |
DisplayFont |
Kingdom Come Display |
Manuscript |
Warhorse Manuscript |
declare const label: NativeClip;
label.setMember("wordWrap", true);label.setMember("multiline", true);label.setText("<b>Bold</b> and plain", true); // true: the engine's HTML subsetUse the game’s artwork
Section titled “Use the game’s artwork”Open a screen against one of the game’s movies to attach the sprites it exports. One screen sees one library; open another screen for a second.
const menuScreen = NativeUI.createScreen({ library: "Menu" });
menuScreen.on("ready", () => { const button = menuScreen.root?.attach("BasicButton"); button?.set({ x: 200, y: 200 });});
for (const library of NativeUI.libraries()) { console.log(`${library.name || "(default)"}: ${library.exports.length} exports`);}Handle input
Section titled “Handle input”screen.focus()takes keyboard, controller and mouse. One screen holds focus at a time, and the game takes it back for anything with higher priority.- While a screen holds focus,
Key.bindhandlers stop firing, as with a focused web view. Close on the screen’sinputevent, never on a key bind. inputhandlers get the action name and its activation mode:kcdc_ui_accept,kcdc_ui_back,kcdc_ui_left,kcdc_ui_right,kcdc_ui_up,kcdc_ui_down. There is a pointer only on mouse and keyboard; a gamepad navigates through these actions.clip.on("press", handler)needs something to hit: draw or attach into an empty clip first. Other mouse events:release,releaseOutside,rollOver,rollOut,dragOver,dragOut.screen.on("event", (name, args) => ...)receives the events a movie declares, with their arguments as a list.- Focus does not pause the game; the world and other players keep moving.
Drive the game’s own screens
Section titled “Drive the game’s own screens”NativeUI.element(name, instanceId) takes a handle on a game element by the
name its XML declares. Instance 0 is the copy the game drives; any other number
is your own private copy, so you do not fight the game for it.
const menu = NativeUI.element("Menu", 47001);
menu.show(); // loads the movie; functions exist only once it is loadedmenu.call("ClearAll", [0]);menu.call("PreparePage", [0, 400, 6, "Kingdoms Connected", 1]);menu.call("AddBasicButton", ["first", 0, "Do the thing", "A tooltip", false]);menu.call("ShowPage", [""]);
menu.on("OnButton", (args) => { Hud.showNotification(`pressed ${String(args[0])}`);});call,setVariable,getVariable,setArray,getArray,setClip,getClipandgotoCliptake names the element’s XML declares;ontakes an event it declares.setArrayis the one call that accepts a list; it fills the game’s list screens.hide()hides at once;requestHide()plays the hide transition.- Reading from an element the game has not loaded answers
nullrather than loading it.
Turn off the game’s own menus
Section titled “Turn off the game’s own menus”NativeUI.setMenuEnabled(menu, false) stops one of the game’s menu screens
from opening, by its key, a controller or a tab inside another menu. Use it
when your resource replaces that screen:
NativeUI.setMenuEnabled("map", false);Key.bind("m", () => Hud.showNotification("Our own map opens here"));NativeUI.isMenuEnabled("map"); // falseNativeUI.setMenuEnabled("map", true); // gives back this resource's hold| Menu | Covers |
|---|---|
inventory |
inventory and item details |
player |
the player, skills and player details |
map |
map and legend |
codex |
codex |
journal |
quest log and diary |
crafting |
crafting |
- An open menu you disable closes on the next tick. Its tab stays visible in the game’s menu but does nothing. Key assignments are left alone.
- Holds are per resource: the menu stays off while any resource disables it,
truereleases only yours, and stopping the resource or ending the session releases them.isMenuEnabledsays whether no resource disables it, not whether the game would open it now. - The escape menu, dialogue, shops and the HUD are not among these; for HUD parts see HUD.
- An unknown menu name throws, and so does
setMenuEnabledoutside a resource.
Ship your own movie
Section titled “Ship your own movie”List the movie in mafiahub.files like any client file, then open a screen in
it. movie and assets are paths inside your resource; layer is where the
screen sits in the game’s stack.
const screen = NativeUI.createScreen({ movie: "ui/myscreen.swf", assets: ["ui/plate.dds"], layer: 46,});Such a screen can attach only what your movie exports and gets no controller
navigation: it suits art with named clips you drive from script.
Lifetime and limits
Section titled “Lifetime and limits”- A screen belongs to the resource that opened it. It closes, with its
handlers, when the resource stops, when the session ends, or on
close(). - If the engine unloads the movie (a level load can), the screen raises
unload, every handle on it stops resolving, and you rebuild on the nextready. - A closed screen or removed clip reports
valid: false, and every call on it fails quietly. - At most 16 screens per resource, 512 mouse handlers per screen, 16 arguments per ActionScript call and 64 KiB per string.
- A shipped movie is at most 32 MiB, with at most 64 extra files beside it.
- There is no layout engine: no flexbox, no reflow, no text measurement beyond what a field reports. If you need those, use a web view.
Related
Section titled “Related”- Show an HTML page (web views): the browser-based alternative.
- HUD messages, nametags and compass: the game’s notifications without building a screen.
- Key binds and controls: input outside a focused screen.
NativeUIreference: every call and option.