← Mods

CairnAPI

lib

v0.7.0

Shared C# layer the other mods build on.

The shared foundation Cairn mods build on — clean, named APIs over the game's internals, so you spend your time on your mod instead of reverse-engineering the plumbing.

Hook into the game's menus, build settings pages, show in-world prompts, read and change the inventory, teleport the climber, and react to game state.

Features

  • Add your own buttons to the main menu, the Settings menu, and the pause menu
  • Open full menu screens of your own — a page rail on the left, native rows on the right — that look and feel like the game's own Settings screen, on the title screen or mid-game
  • Build native settings pages — toggles, sliders, dropdowns, text fields, and buttons — usable with keyboard, mouse, or controller
  • Show button prompts on the HUD or floating in the world, with icons that match the player's input device
  • Make things interactable by walking up to them, or by reaching out and grabbing them while climbing
  • Read and change the player's inventory, and look up any item in the game
  • Teleport the climber anywhere — the target area streams in automatically
  • Enumerate the game's worlds, zones, and story beats
  • Know the current game state (menu, gameplay, cutscene…) and react to transitions

Requires

MelonLoader only.


ActionButton

A bottom-strip text action button (the native "Return"/"Reset" style), with an optional live keycap glyph at its left.

ActionButton.Root

The button's GameObject.

ActionButton.Rect

The RectTransform (authored size 200×50; resize or let a layout group drive it).

ActionButton.Selectable

The underlying uGUI Selectable, for navigation wiring.

ActionButton.Create(parent, label, onClick, glyphAction?)

Create an action button under parent. Click / Submit fires onClick. Returns null on failure (game UI not loaded yet).

parent RectTransform Where to attach (typically a bottom HorizontalLayoutGroup strip).
label string Button text.
onClick Action Fired on click / Submit.
glyphAction opt InputAction Optional input action whose keycap renders left of the button (see CairnAPI.Glyph).
ActionButton.SetLabel(text)

Change the label text.

text string
ActionButton.SetInteractable(interactable)

Enable/disable interaction (native disabled tint).

interactable bool
ActionButton.Select()

Move uGUI selection to this button.

ActionButton.Destroy()

Tear the button down. Safe to call more than once.

Example
var b = ActionButton.Create(bar, "Return", Close, Glyph.Action(GameAction.UICancel));

AddResult

Return value from Inventory.Add.

AddResult.Ok

True if all requested items were added.

AddResult.Added

How many were actually added.

AddResult.Error

Failure reason when Ok is false.

Assets

Load any of the game's assets by Addressables key, from any game state — the title screen included. Every asset the game ships (prefabs, ScriptableObjects, materials, textures, timelines) is in the Addressables catalog; there is never a reason to wait for gameplay so a bundle happens to be loaded, or to clone a live scene object as a substitute for the real asset. Keys are forgiving: pass the full catalog address, the asset's GUID, or just the bare asset name (Assets.Load("GlobalUIs")) — the catalog is parsed at first use and names resolve to their real address. Loaded handles are cached and held so the asset (and anything you Instantiate from it) stays valid; call Assets.Release only when a mod is genuinely done with an asset.

Assets.TryResolveKey(query, key, typeName?)

Resolve a query (exact catalog key, GUID, full path, or bare asset name — case-insensitive) to the exact catalog key. When several assets share a bare name, typeName (e.g. "GameObject") picks between them. Returns false when nothing matches.

query string
key string
typeName opt string
Assets.FindKeys(substring)

All catalog keys containing substring (case-insensitive) — discovery for tooling and exploratory code. GUID keys are included.

substring string
Assets.Load``1(keyOrName)

Load an asset synchronously. T is the expected asset type (GameObject for prefabs); the result is the ASSET, not an instance — Instantiate what you need from it. Returns null (with a logged warning) for unknown keys, failed loads, and type mismatches. The underlying Addressables handle is cached and held, so repeat calls are free and the asset stays valid until Assets.Release.

keyOrName string
Assets.LoadAsync``1(keyOrName, onReady)

Load an asset without blocking; onReady fires on the main thread with the asset, or null on failure — synchronously when the asset is already cached. Same caching and resolution semantics as Assets.Load%60%601.

keyOrName string
onReady Action<T>
Assets.Release(keyOrName)

Release a previously loaded asset's Addressables handle. After this the asset (and clones of it) may be unloaded by the engine — only call it when the mod is done with the asset for good.

keyOrName string

Beat

A story-beat sensor location.

Beat.Label

Authored beat name.

Beat.Position

World-space center of the sensor trigger.

Beats

Enumerate story-beat sensors in the current scene.

Beats.Available bool

True when the story manager is live. Check before calling Snapshot.

Beats.Snapshot() List

Every story-beat sensor in the current scene, sorted by label. Pure — no caching.

Example
if (!Beats.Available) return;

var beats = Beats.Snapshot();
foreach (var b in beats)
    Log($"{b.Label}  @{b.Position}");

Teleport.To(Stance.Ground(beats[0].Position));

Belay

The climbbot's belay as state a teleport must MANAGE, not destroy. The game attaches/secures the bot itself on climbing-mode entry (proven live: the bot re-attached ~30ms after a wall arrival), so the rules are: • a placement that yanks a BELAYED climber stands the belay down first (else the rope + its quickdraws stay anchored to the old wall across the jump); • a climbing arrival re-secures — natively when the placement crosses a mode edge, explicitly via Belay.Resume when it doesn't (wall→wall keeps the mode, so no native attach fires); • a ground arrival stays detached — the native attach re-arms on the next climb. Never stand the belay down outside a placement (a spawn-time stand-down fights the game's own attach).

Belay.Active

A climbbot is currently attached to the climber's harness.

Belay.StandDown()

Stand the belay down (stop securing + detach the rope) — the bot's own setters in its recall flow's order. Safe no-op when not belayed. Only call around a placement.

Belay.Resume()

Re-establish the belay after a placement that ended in CLIMBING without a mode edge (the native attach only fires on entry into climbing). No-ops when the pawn isn't climbing — SetSecureClimber's own mode check guards it — or when no bot exists.

Bookmark

One saved bookmark: a named world position bound to the map it was placed on. A bookmark captured while climbing also carries the verbatim on-wall pose.

Bookmark.Pose

The verbatim pose captured with the bookmark, or null for a ground bookmark (existing stores load with no pose and behave exactly as before).

Bookmark.Position

The bookmark's world position.

Bookmark.OnWall

True when this bookmark was captured on the wall (it carries a climbing pose).

Bookmarks

Saved warp-point bookmarks, shared across mods. A bookmark is a named world position on a specific map; while that map is loaded it appears in the eagle-eye fast-travel list as a warpable destination. Add, rename, and remove here — materializing the live warp points (register on gameplay load, re-anchor on zone change, stand down on session end) is automatic.

Bookmarks.OnRegistryChanged

Fires when the live warp-point registry changes wholesale — after a lifecycle stand-down (session end, zone change) and after a rebuild completes. UIs holding warp-point rows should re-pull them.

Bookmarks.OnCurrentMap()

Every bookmark saved for the current map, or an empty list when not in a level.

Bookmarks.ForMap(mapKey)

Every bookmark saved for an explicit map key (a shipped mountain's world name, or a custom level's "cml:" address — the same key World.CurrentMapKey reports in-level). For menu-time enumeration, when no world is loaded. Null or empty key → empty list.

mapKey string
Bookmarks.Add(name?, allowOnWall?)

Save a bookmark at the local climber's current spot on the current map. Standing on the ground saves a plain position; a stable climbing stance saves the verbatim on-wall pose with it. Pass allowOnWall false when the calling surface can only manage ground bookmarks — an on-wall capture is then refused (the grounded-only behavior). A null or blank name gets a default. Returns null when the climber is not spawned or is mid-move (falling, reaching, on the rope, or off every hold) — those states can't be captured.

name opt string
allowOnWall opt bool
Bookmarks.Add(position, name?)

Save a bookmark at an explicit world position on the current map. A null or blank name gets a default. Returns null when not in a level.

position Vector3
name opt string
Bookmarks.Rename(bookmark, name)

Rename a bookmark and persist; its warp-list row updates on the game's next refresh.

bookmark Bookmark
name string
Bookmarks.Remove(bookmark)

Remove a bookmark and its live warp point, if any. Returns false if unknown.

bookmark Bookmark
Bookmarks.ForWarpPoint(warpPoint)

The bookmark behind a live warp point, or null if the point is not a bookmark's.

warpPoint FreeRoamWarpPoint
Bookmarks.LocKeyOf(bookmark)

The loc key rendering a bookmark's name while it is materialized (for live edits via Localization.Update), or default when it has no live point.

bookmark Bookmark
Bookmarks.WarpConfirmed

Fires when a bookmark is warp-confirmed from the eagle-eye view (after the pawn is placed). A session mod (Boulderdash) uses it to fold the arrival into its own run/restart bookkeeping.

CachedIndex<TKey, T>

Caches a scan's results indexed by key (e.g. LootProvider by UniquePersistentID). A miss rebuilds the whole index in one scan rather than scanning per lookup — turns an O(n) scan repeated m times (once per point-query) into one O(n) scan plus m O(1) dictionary lookups.

CachedLookup<TKey, T>

Caches independent results keyed by an arbitrary value (e.g. a font atlas texture, a template-array pointer). Unlike CairnAPI.CachedRef%601, multiple keys stay cached simultaneously instead of evicting each other — use when the same call site legitimately queries more than one distinct key over the object's lifetime (e.g. a two-rung "prefer X, else Y" fallback).

CachedRef<T>

Caches a single resolved instance. A live (non-null, Unity's overridden operator) cached value short-circuits the scan entirely. An optional key lets the cache self-invalidate when the caller's identity changes (e.g. a respawn swaps which pawn is "local", or the active scene changes) even though the old cached value may still technically be non-null.

CachedRef.Get(resolve)

Resolve once and hold forever (until Unity-null). A null result is remembered too — resolve() won't run again unless CachedRef%601.Invalidate is called. Use when a null result means "confirmed absent, and nothing else here would make it appear" (e.g. a fixed, load-once asset).

resolve Func<T>
CachedRef.GetUntilFound(resolve)

Same, but a null result is NOT remembered — every call re-resolves until resolve() finally succeeds, then stays cached from then on. Use for a transient condition you're waiting on (e.g. "has the pawn spawned yet") where retrying every call is the point.

resolve Func<T>
CachedRef.Get``1(key, resolve)

Resolve and cache, but re-resolve (including re-trying a previously-null result) whenever key differs from the key last used to produce the cached value — e.g. a scene name, so "no MainMenu in this scene" stays cached until the scene actually changes.

key TKey
resolve Func<T>

CachedScan<T>

Caches the full result of a scan (e.g. every loaded InputActionAsset) until explicitly invalidated. Use when a caller needs to enumerate ALL matching instances repeatedly, not look up one by key — the instances themselves are stable even though which of them are individually "active" varies per call.

CairnMenu.MainMenuRail

CairnMenu.MainMenuRail.AddScreen(label, buildScreen)

Add a main-menu entry that opens a mod CairnAPI.MenuScreen, behaving just like the game's own Settings button on the title screen: clicking it slides the main menu away and opens the screen built by buildScreen; backing out returns to the main menu. The entry sits above the Settings button. Returns a handle that removes the entry when disposed.

label string
buildScreen Func<MenuScreen>
CairnMenu.MainMenuRail.AddEntry(label, onClick)

Add a title-screen mode-select entry, slotted directly above the native Settings button.

label string
onClick Action
CairnMenu.MainMenuRail.AddEntry(label, onClick, insertBefore)

Add a title-screen mode-select entry directly above the native button GameObject named insertBefore (e.g. "SettingsButton"). Matched by GameObject name; if no child matches, the entry appends. The entry is injected on every MainMenuModeSelectElement.Awake and spliced into the native nav set via a GetButtons() postfix.

label string
onClick Action
insertBefore string

CairnMenu.PauseMenuRail

CairnMenu.PauseMenuRail.AddEntry(label, onClick)

Add a pause-rail entry at the bottom of the rail.

label string
onClick Action
CairnMenu.PauseMenuRail.AddEntry(label, onClick, insertBefore)

Add a pause-rail entry directly above the native rail child named insertBefore (e.g. "RetryFromStart" to sit just after Settings). The anchor is matched by GameObject name and exists even when that native button is hidden, so the slot is stable across conditional buttons; if no child matches, the entry appends.

label string
onClick Action
insertBefore string
CairnMenu.PauseMenuRail.AddEntry(label, onClick, insertBefore, visible)

As above, plus a visibility predicate evaluated each time the pause menu opens — the entry is only injected while it returns true (e.g. gate a session-scoped tool on the session being live). A throwing predicate hides the entry.

label string
onClick Action
insertBefore string
visible Func<bool>

CairnMenu.SettingsRail

CairnMenu.SettingsRail.AddPage(label, buildFields)

Add a rail entry that opens a managed CairnAPI.SettingsPage — a native fieldsUI-backed page populated from buildFields. The returned page can swap its content live via SettingsPage.Refresh / SettingsPage.SetFields.

label string
buildFields Func<Field[]>

Cameras

Cameras.Reseat()

Re-seat the gameplay camera behind the pawn NOW — the native "climber reset" verb. Selects the current camera (ForceCameraChangeNow, byte-identical to CheckCurrentCamera) and resets the live rig (repositions its look-at pivot and computes the behind-her rotation). Mirrors the native teleport chain, which our teleport pipeline doesn't otherwise trigger. Returns false if the camera system isn't up or the call failed.

Cameras.EagleViewActive

True while any eagle-eye view (plain / plus / free / route-scouting) is the active camera — the read-only observer for Cameras.Reseat's camera family. False on any failure.

Clock

The game clock — a day-seconds float owned by the game's time system. Reads fail soft (zero) when no session is up. Writes are deliberately SILENT (the game's bare clock write): survival systems do not react, so they're right for corrections, replication, and scripted setups. There is no wrapper for the event-firing setter — passing time "for real" (hunger ticks, day count) belongs to real sleeps at bivouacs.

Clock.GameTime

The game clock in day-seconds (wraps daily; 3600 = 1:00 AM). 0 when no session is up.

Clock.Day

How many in-game days have passed.

Clock.TimeOfDay01

Time of day as 0..1 across the current day (0.5 = noon).

Clock.Paused

Whether the game clock is currently paused (menus, cinematics, photo mode).

Clock.SetSilently(daySeconds)

Set the clock to an absolute day-seconds value, silently (no survival side effects). Returns false when no session is up.

daySeconds float
Clock.SetSilently(hours, minutes?)

Set the time of day within the current day, silently (no survival side effects).

hours int
minutes opt int

CrossMenu

CairnAPI cross-menu subsystem. Lets other mods add actions to Cairn's cross-menu, and adds new LT+chord "extra menus" of their own. Define menus by chord, then register actions into them. Static façade in the CairnAPI per-subsystem idiom: CrossMenu.Install does the one-time Il2Cpp/Harmony setup (called from Core.OnInitializeMelon); CrossMenu.Tick pumps the menu controller every frame (called from Core.OnUpdate).

CrossMenu.BaseMenu

The vanilla LT wheel (level-0). Actions here use only its free slots.

CrossMenu.DefineMenu(menuId, chord)

Define (or update) a menu selected by holding LT + the given modifier chord. Two mods must not claim the same chord; the first wins and a warning is logged. The base menu (LT alone) is implicit and need not be defined.

menuId string
chord CrossMenuModifier
CrossMenu.Register(action)

Register (or replace, by Id) a custom action. Safe to call before the HUD exists.

action CrossMenuAction
CrossMenu.Unregister(id)

Remove a previously-registered action by Id. No-op if unknown.

id string
CrossMenu.Ready

True once the live menu is found and the library is driving it.

Example
CrossMenu.DefineMenu("mymod.combat", CrossMenuModifier.RightTrigger);   // LT+RT
CrossMenu.Register(new CrossMenuAction {
    Id = "mymod.grapple", Label = "Grapple", IconName = "anchor",
    Menu = "mymod.combat", Direction = CrossMenuDir.Up,
    OnExecute = () => DoGrapple(),
});

CrossMenuAction

A custom cross-menu action a mod registers. The library owns all Il2Cpp/render/dispatch plumbing; a mod supplies identity, which menu + direction it occupies, an icon, and the behaviour callbacks.

CrossMenuAction.Id

Stable unique id, e.g. "mymod.grapple". Re-registering the same id replaces it.

CrossMenuAction.Label

Shown in logs and (future) tooltips.

CrossMenuAction.Menu

The menu this action lives in — a menu id previously passed to CrossMenu.DefineMenu. Defaults to CrossMenu.BaseMenu (the vanilla LT wheel — only its free slots may be used).

CrossMenuAction.IconName

A built-in Lucide icon name (e.g. "anchor", "flame"). Used when CrossMenuAction.Icon is null.

CrossMenuAction.Icon

Explicit icon sprite; takes precedence over CrossMenuAction.IconName. Null → placeholder.

CrossMenuAction.DisplayCount

If true a numeric badge (from CrossMenuAction.GetCount) is drawn on the icon.

CrossMenuAction.CountWarningMaxValue

At or below this count the badge turns to the warning colour. Only when DisplayCount.

CrossMenuAction.OnExecute

Invoked when the action is executed (after the hold-to-confirm). Required.

CrossMenuAction.IsAvailable

Return false to grey-out / block. Optional — default always-available.

CrossMenuAction.GetCount

Numeric badge value when CrossMenuAction.DisplayCount is set. Optional — default 0.

CrossMenuAction.OnFailedExecute

Invoked when attempted-but-unavailable. Optional.

CrossMenuDir

One of the four radial directions. Mirrors the game's CrossMenuUI.Direction.

CrossMenuDir.Up

CrossMenuDir.Right

CrossMenuDir.Down

CrossMenuDir.Left

CrossMenuModifier

Extra gamepad modifiers — held in addition to the left trigger — that select a menu. LT alone is the base (vanilla) wheel; LT + a chord of these selects a mod menu. Combine with '|' (e.g. CrossMenuModifier.RightTrigger, or RB|LB for a two-button chord).

CrossMenuModifier.None

CrossMenuModifier.RightTrigger

CrossMenuModifier.LeftBumper

CrossMenuModifier.RightBumper

Cycler

THE CYCLE WIDGET — the game's own "label ‹ value ›" arrows row (the exact FieldListArrows the settings menus render), lifted out of the menu-screen context as a standalone palette widget: host it in any RectTransform (the eagle-eye prompt band, a HUD line, a widget page) and drive it by Cycler.Index. Rendering, arrow buttons, and value refresh are entirely the native row (the shared donor-template machinery under CairnAPI.FieldRows); this wrapper owns only a compact, layout-group-friendly container and the model. Null from Create when no donor templates exist yet (build once a menu/gameplay host is up).

Cycler.Rect

The widget's container — anchor/place it like any child (it also carries a LayoutElement, so layout-group hosts flow it inline).

Cycler.Create(parent, label, options, index, onChanged, width?, height?)

Build the native arrows row under parent. onChanged fires with the new option index — from the arrow buttons AND from programmatic Cycler.Index writes (hotkey-driven cycling).

parent RectTransform
label string
options string[]
index int
onChanged Action<int>
width opt float
height opt float
Cycler.EnsureFitted()

One-shot post-materialize normalization for standalone hosts — the row prefab is authored for the full settings-panel width (prefab-measured: label cell 0–40%, value cluster 60–100%, the value text spanning the WHOLE cluster with the 32px arrows floating on its ends, and the right arrow pivoted to hang 32px PAST the row edge). At widget widths (~480px) that collides. Retune: label 0–30%, cluster 30–100%, right arrow pivoted inside, text inset clear of both arrows. Call per frame (rows materialize a frame after build via the game's deferred refresh); no-ops once applied.

Cycler.Index

The selected option. Setting it drives the NATIVE row refresh (and the onChanged callback) through the model's own Index setter; an unchanged value is a no-op.

Cycler.Destroy()

Tear the widget down. Safe to call more than once.

FieldRows

The game's own settings rows (the ones CairnAPI.Fields builds) hosted inside a container you own — for mixing native rows into a custom widget page. Create with the rows, or FieldRows.Set later. Returns null from Create when the game UI isn't loaded yet.

FieldRows.Rect

The rows' RectTransform — anchor/place it like any child; height auto-fits.

FieldRows.Create(parent, fields)

Build native rows under parent. Top-anchored, parent-width, auto-height; re-anchor FieldRows.Rect to place. Null when no donor templates exist yet (build once a menu or gameplay host is up).

parent RectTransform
fields Field[]
FieldRows.Valid

True while the host and its donor templates are alive.

FieldRows.Set(fields)

Replace the rows (the game's own RemoveAll → Add → Activate cycle).

fields Field[]
FieldRows.Selectables()

The rows' Selectables in visual (sibling) order — for wiring explicit navigation between the rows and neighbouring controls. Live query: rows are born a frame after FieldRows.Set (the game's deferred Refresh), so call this from a later frame; empty until then.

FieldRows.LastSelectable()

The actual Selectable the game focuses on the LAST navigable row (native FieldsUI.GetLastSelectable) — not the first child Selectable FieldRows.Selectables returns, which on a value row (ListArrows/slider) can be an inner arrow. Use this when wiring a control BELOW the rows: UI.FieldsUI re-derives its rows' Navigation struct on every selection change (FieldUI.SetNavigation), nulling the bottom field's selectOnDown — so re-assert the link to this selectable each frame, don't set it once. Null when no rows / host dead.

FieldRows.FirstSelectable()

The actual Selectable of the FIRST navigable row (native FieldsUI.GetFirstSelectable) — the counterpart to FieldRows.LastSelectable for wiring a control ABOVE the rows.

FieldRows.SelectFirst()

Hand EventSystem focus to the first selectable row.

FieldRows.Destroy()

Tear the rows down and invalidate the handle. Safe to call more than once.

Fields

Fields.PillButton(label, buttonLabel, onClick)

A settings row with a REAL pill-chromed button as its widget — label on the left, button on the right (unlike Fields.Button, where the whole chromeless row is the button).

label string Row label (left column).
buttonLabel string Text on the pill button.
onClick Action Fired when the button is clicked / confirmed.
Fields.Grid(label, cells, initialIndex, onChanged)

A grid of icon+label cells the player clicks to pick one. Renders in settings, photo mode, and debug menu pages alongside the other field rows.

label string
cells (Sprite icon, string label)[]
initialIndex int
onChanged Action<int, int>
Fields.VectorSlider(label, initial, onChanged, min, max, wholeNumbers?)

A 2-component row of sliders for editing a Vector2, e.g. a min/max or X/Y pair.

label string
initial Vector2
onChanged Action<Vector2, Vector2>
min Vector2
max Vector2
wholeNumbers opt bool
Fields.VectorSlider(label, initial, onChanged, min, max, wholeNumbers?)

A 3-component row of sliders for editing a Vector3, e.g. an X/Y/Z offset.

label string
initial Vector3
onChanged Action<Vector3, Vector3>
min Vector3
max Vector3
wholeNumbers opt bool
Fields.VectorSlider(label, initial, onChanged, min, max, wholeNumbers?)

A 4-component row of sliders for editing a Vector4, e.g. a color or a rect.

label string
initial Vector4
onChanged Action<Vector4, Vector4>
min Vector4
max Vector4
wholeNumbers opt bool
Fields.VectorText(label, initial, onChanged, min, max, wholeNumbers?)

A 2-component row of text inputs for editing a Vector2, e.g. a min/max or X/Y pair.

label string
initial Vector2
onChanged Action<Vector2, Vector2>
min Vector2
max Vector2
wholeNumbers opt bool
Fields.VectorText(label, initial, onChanged, min, max, wholeNumbers?)

A 3-component row of text inputs for editing a Vector3, e.g. an X/Y/Z offset.

label string
initial Vector3
onChanged Action<Vector3, Vector3>
min Vector3
max Vector3
wholeNumbers opt bool
Fields.VectorText(label, initial, onChanged, min, max, wholeNumbers?)

A 4-component row of text inputs for editing a Vector4, e.g. a color or a rect.

label string
initial Vector4
onChanged Action<Vector4, Vector4>
min Vector4
max Vector4
wholeNumbers opt bool

FieldsPanel

FieldsPanel.Create(title?, width?)

Build a hidden panel that will host native settings rows. The panel is created but NOT shown — call FieldsPanel.Show after adding fields. Row visuals come from the game's own settings-row templates, acquired once at build time. Returns an invalid handle (all methods no-op) if the game hasn't loaded its UI yet — build the panel once a menu or gameplay is up.

title opt string Optional heading drawn above the rows; null = no header.
width opt float Panel width in reference pixels (height auto-fits the rows).
FieldsPanel.Valid

True once the panel is built and its FieldsUI + row templates are still alive.

FieldsPanel.Visible

True while the panel is on-screen (between FieldsPanel.Show and FieldsPanel.Hide).

FieldsPanel.Add(fields)

Add native rows for the given game UI.Field data objects (the ones CairnAPI.Fields builds). Rows are born inactive and appear a frame later via the game's own deferred Refresh — do not fight it. Repeated Add of the same Field is NOT deduplicated; call FieldsPanel.Clear before rebuilding. Keep the total under ~12 rows (no scroll in v1).

fields Field[]
FieldsPanel.Show()

Show the panel and hand focus to its first row (EventSystem row-nav then works). Idempotent. The game supplies the EventSystem; without one, rows draw but can't be navigated.

FieldsPanel.Hide()

Hide the panel (rows and their state are kept; call FieldsPanel.Show to reveal again).

FieldsPanel.Clear()

Destroy every current row (the game's own RemoveAll — unbinds, stops coroutines, destroys row GOs).

FieldsPanel.Destroy()

Tear the panel down entirely and invalidate the handle. Safe to call more than once.

GameAction

Friendly names for the game actions a custom prompt most commonly echoes. See Glyph.Action.

GameAction.Interact

GameAction.SharePath

GameAction.Confirm

GameAction.Cancel

GameAction.Navigate

GameAction.Pause

GameAction.Rest

GameAction.Rappel

GameAction.AscendRope

GameAction.GrabRope

GameAction.Rewind

GameTime

GameTime.PauseGameplay()

Request a gameplay pause — freezes the simulated world (climber, physics) while leaving the camera and UI on the engine clock. Reference-counted; balance every call with GameTime.UnpauseGameplay. Returns false if the time system isn't up.

GameTime.UnpauseGameplay()

Release one gameplay-pause request. GUARDED against the OnLevelLoading drain trap: TimeManager.OnLevelLoading drains the pause-request counter to zero on every level load, so a request held across a reload is ALREADY released by the game — decrementing afterward would drive the counter negative and silently eat a future pause. So when the pawn is despawned (a level load in flight) or there is no world at all, the decrement is SKIPPED and this returns false. Otherwise it releases and returns true.

GameTime.GameplayPaused

True while gameplay is paused (the request counter is above zero) — the read-only observer for the pause verbs. False on any failure.

Glyph

Glyph.Action(action)

The player's live InputAction for a curated game action (reflects their current rebind), or null if the input system isn't ready yet. Hand the result to a Prompt as its glyph.

action GameAction
Glyph.Named(mapSlashAction)

Resolve any game action by its "Map/Action" (or bare "Action") name against the live input asset — the escape hatch for actions not in the CairnAPI.GameAction enum. Null if not found / not ready.

mapSlashAction string
Glyph.Key(key)

A glyph for a raw keyboard key, e.g. Glyph.Key("g"). Special keys (enter/space/esc/tab/arrows…) resolve to a stock sprite; plain letter/number keys have no sprite in the icon DB, so they render as the human-readable key text ("G") — exactly as the game does. See CairnAPI.Glyph.

key string
Glyph.Path(controlPath)

A glyph for an arbitrary control path, e.g. Glyph.Path("/buttonSouth"). Buttons + special keys resolve to a stock sprite; anything without a DB sprite renders as human-readable text.

controlPath string
Glyph.Custom(name, bindingPaths)

A cross-device action with MULTIPLE bindings (e.g. a keyboard key AND a gamepad button), enabled so it fires on either device, and usable BOTH as a prompt glyph (the glyph + adaptiveBinding auto-picks the active device's binding, so the keycap swaps to the pad button on a controller) AND as live input (poll action.WasPerformedThisFrame()). This is the parity path: bind "/b" + "/buttonWest" and the same action drives the icon and the trigger on both devices. name must be unique per logical action (it keys the action in the shared map).

name string
bindingPaths string[]
Glyph.Asset

The live InputActionAsset the game is driving (player's bindings live here), or null pre-game.

GlyphImage

GlyphImage.Root

The widget's GameObject (an Image the native component drives). Parent/position freely.

GlyphImage.Rect

The RectTransform, for layout.

GlyphImage.Create(parent, action, size?)

Create an inline glyph image under parent showing the sprite for action's current binding (see CairnAPI.Glyph for obtaining actions). The icon tracks device changes and rebinds natively. Returns null if construction fails; a null action is allowed — the glyph stays hidden until GlyphImage.SetAction is called.

parent RectTransform Transform to nest under (layout groups size it via its RectTransform).
action InputAction The input action whose binding the glyph renders, or null for none yet.
size opt float Square edge length in reference pixels (native prompt glyphs are ~60).
GlyphImage.Create(parent, action, size?)

Create showing the player's current binding for a curated CairnAPI.GameAction.

parent RectTransform
action GameAction
size opt float
GlyphImage.SetAction(action)

Point the glyph at a different action (it re-renders; null hides it).

action InputAction
GlyphImage.SetBindingIndex(index)

Show a specific binding of the action instead of the device-adaptive pick.

index int
GlyphImage.Destroy()

Tear the glyph down. Safe to call more than once.

Holds

Whether the streamed climbing holds have arrived at a position. A level loads a low-detail wall first and streams the real holds subscene in a moment later; until the hold behaviours register (they do so in OnEnable) and answer with candidates, a climbing placement there has nothing to grip. Holds.ReadyAt is that readiness signal — the scene's own grab-candidate lookup answering with holds IS the "the wall is here now" edge a race-safe on-wall spawn waits on.

Holds.ReadyAt(pos)

True when the streamed climbing holds are present around pos — at least one registered SceneHoldsSpatialPartitioning answers with candidate holds there. False (never throws) while the holds subscene is still streaming in, or when the scene state can't be read.

pos Vector3

HudPanel

HudPanel.Content

The region to build panel content under (full-screen stretch; anchor your own layout).

HudPanel.Create(name?, fadeDuration?, sortingOrder?)

Build a hidden HUD panel with the native open/close fade lifecycle. Build content under HudPanel.Content, then HudPanel.Open. The panel survives scene loads. Returns an invalid handle (all methods no-op) if construction fails.

name opt string GameObject name (diagnostics); null = a default.
fadeDuration opt float Open/close fade seconds (unscaled). Must be > 0 for the async fade.
sortingOrder opt int Canvas order: over the game HUD, under the pause menu (1000) by default.
HudPanel.Valid

True once built and still alive.

HudPanel.IsOpen

True while the panel is open or fading in (the native state query).

HudPanel.Open()

Open with the native fade-in. Idempotent while already open.

HudPanel.Close()

Close with the native fade-out. Idempotent while already closed.

HudPanel.SnapOpen()

Snap open/closed without the fade (the native ForceOpen/ForceClose path).

HudPanel.SnapClosed()

Snap closed without the fade.

HudPanel.Destroy()

Tear the panel down entirely and invalidate the handle. Safe to call more than once.

IMenuWidget

A content widget hostable inside a CairnAPI.MenuScreen page (see MenuScreen.AddWidgetPage). The screen calls IMenuWidget.FocusFirst when the page opens and IMenuWidget.Destroy when it closes — the widget owns everything in between.

IMenuWidget.FocusFirst()

Move UI focus to the widget's first selectable element (called when its page opens).

IMenuWidget.Destroy()

Tear the widget down (called when its page closes or the screen is destroyed).

IWarpSource

A contributor of destinations to the eagle-eye fast-travel list. Register with WarpSources.Register; the active source's IWarpSource.Entries are materialized as live warp points, and selecting one routes to IWarpSource.Confirm (never the native warp — so no loading screen and full control over what "arrive" means: teleport, start a run, …). Rename/Delete drive the in-view edit keybinds. Call WarpSources.Invalidate when your entries change.

IWarpSource.Label

Short label for the source toggle prompt ("Bookmarks", "Routes").

IWarpSource.Entries()

The destinations for the CURRENT map (the source reads World.CurrentMapKey itself). Called on every (re)materialize; return a fresh list.

IWarpSource.Confirm(entry)

Arrive at a selected entry. Runs INSTEAD of the native warp (which is skipped), so this owns placement — use Teleport.To with a CairnAPI.Stance, or start a run; never the native WarpToPoint.

entry WarpEntry
IWarpSource.CanEdit(entry)

Whether this entry may be renamed/deleted from the eagle-eye view.

entry WarpEntry
IWarpSource.Rename(entry, newName)

Rename an editable entry (persist + WarpSources.Invalidate).

entry WarpEntry
newName string
IWarpSource.Delete(entry)

Delete an editable entry (persist + WarpSources.Invalidate).

entry WarpEntry
IWarpSource.Available

Whether this source is currently offerable at all — it only counts toward the toggle, can be switched to, and materializes while true. Bookmarks are always available; routes only inside a Boulderdash session, so in a plain campaign the routes list and its toggle never appear.

IWarpSource.CanAddHere

Whether the "add here" keybind applies to this source (bookmarks capture the climber's spot; sources whose destinations are authored elsewhere — routes are recorded — return false).

IWarpSource.ListsNativePoints

Whether the game's OWN warp points stay in the eagle-eye list while this source is active. Bookmarks say yes (native destinations belong with them); routes say no (the list shows routes only — natives are pulled while active and restored on toggle/stand-down).

IWarpSource.NativeLabel

Label for the game-provided entries this source can show/hide from its list ("game points", "game routes"), or null when it has none — the eagle-eye "show/hide" keybind only appears for a labelled source. The view flips IWarpSource.NativeShown and re-materializes via WarpSources.Refresh.

IWarpSource.NativeShown

Whether the game-provided entries are currently shown in this source's list.

IWarpSource.SelectorOptions

Optional in-view option cycler shown while this source is active (routes offer the launch mode). Null/empty = no selector; the view renders ":

IWarpSource.SelectorLabel

What the selector chooses (e.g. "Mode") — the prompt's label prefix.

IWarpSource.SelectorIndex

The selected option (index into IWarpSource.SelectorOptions); the view writes it as the player cycles.

IWarpSource.AddHere()

Author a new destination at the climber's current spot. Returns true if one was added (the controller then rebuilds the list). No-op / false when unsupported.

Inventory

Add items to and query the player's inventory.

Inventory.Add(id, count?) AddResult

Add items to the appropriate storage slot. Stops cleanly at capacity.

id InventoryItemStringIdEnum Item to add.
count opt int How many to add.
Inventory.Count(id) int

How many of an item the player currently holds.

id InventoryItemStringIdEnum Item to count.
Inventory.StorageWeight(storage) float

Current total weight in a storage slot.

storage StorageType Which slot to query.
Inventory.MaxBagWeight() float

The bag's weight capacity.

Example
var result = Inventory.Add(InventoryItemStringIdEnum.Food_Nuts, 3);
if (!result.Ok) LogWarning(result.Error);
else Log($"Added {result.Added}");

int nuts  = Inventory.Count(InventoryItemStringIdEnum.Food_Nuts);
float bag = Inventory.StorageWeight(StorageType.Bag);

ItemGrid

ItemGrid.Root

The grid's root GameObject.

ItemGrid.Create(parent, entries, onConfirm, columns?, cellSize?, spacing?)

Build a scrollable native item grid under parent. onConfirm fires with the entry index on click / gamepad Submit. Returns null when the native cell template isn't available yet.

parent RectTransform Content region to fill (e.g. a widget page host).
entries IReadOnlyList<ItemGridEntry> The items (and count badges) to show, in grid order.
onConfirm Action<int> Fires with the picked entry's index.
columns opt int Cells per row (navigation math derives from this).
cellSize opt float Cell edge in reference pixels; 0 = the cell's native authored size.
spacing opt float Gap between cells.
ItemGrid.Count

Number of cells.

ItemGrid.FocusFirst()

Focus the first cell (gamepad/keyboard nav anchors here).

ItemGrid.SetEntry(index, entry)

Re-bind one cell to a different item/count in place.

index int
entry ItemGridEntry
ItemGrid.Destroy()

Tear the grid down. Safe to call more than once.

ItemGridEntry

One grid entry: a game item and the count badge to show on its cell.

ItemGridEntry.Item

The item to display.

ItemGridEntry.Count

Count shown on the cell's native badge.

ItemInfo

Per-item metadata.

ItemInfo.Id

Enum identifier.

ItemInfo.Name

Display name.

ItemInfo.StoredIn

Which storage slot holds this item.

ItemInfo.MaxCount

Maximum stack count.

ItemInfo.HasIcon

True when the item ships real icon art (not the game's placeholder icon).

ItemInfo.Icon

The item's icon sprite, shared by reference; null when the item ships no real art (the game's placeholder icon — see ItemInfo.HasIcon).

ItemInfo.UnitWeight

Weight per unit. NaN for non-physical items.

ItemLocation

A world site that yields inventory items when interacted with — a foraged plant, a cache, a bag, a multi-item container. Identified by the game's own stable per-node id, which is deterministic across launches and saves (it is the same key the game's save system uses to remember which pickups were consumed).

ItemLocation.Id

Stable unique id of this location (the game's persistent provider id).

ItemLocation.Name

Name of the GameObject hosting the pickup (diagnostic).

ItemLocation.SceneName

Name of the scene the pickup lives in.

ItemLocation.Position

World position of the pickup.

ItemLocation.Items

The item yielded per slot, in slot order. Single pickups have one entry; containers have several.

ItemLocation.IsContainer

True when the site holds more than one slot (opens the native item carousel).

ItemLocation.CanLoot

Whether the site can currently be looted (not emptied, not gated).

ItemLocations

World item-location API — enumerate every item pickup in the loaded world by stable id, and override what any of them yields (and the name shown at it). The foundation for randomizers: an override makes the site give — and label itself as — a different item, natively. Containers show the overridden items' icons in the game's own carousel automatically. Overrides are durable for the session: they are applied to live nodes immediately, re-applied automatically when a scene (re)loads or a save is loaded, and never touch the shared loot assets — only the one node. They are not written to the save file; re-register them each session (a seeded randomizer recomputes them anyway).

ItemLocations.Enumerate()

Every item location in the currently loaded scenes. Only sites with a stable id (finite-stock pickups) are returned; infinite sources (e.g. bottomless bushes) are not item locations. Never throws; empty when no world is loaded.

ItemLocations.Find(id)

The location with the given id, if it is loaded right now. Null otherwise.

id ulong
ItemLocations.Override(id, items, label?)

Register a durable override: the location yields items (one per slot) and — for single pickups — shows label as its world-prompt name (defaults to the first item's own name). Applied now if the node is loaded, and re-applied whenever the game (re)creates it. Replaces any previous override for the same id.

id ulong
items InventoryItemStringIdEnum[]
label opt LocKeyStringId?
ItemLocations.OverrideSingle(id, item)

Convenience for the common single-slot case; the prompt name follows the item.

id ulong
item InventoryItemStringIdEnum
ItemLocations.ClearOverride(id)

Remove the override for a location, restoring its original loot and label (takes effect immediately if the node is loaded).

id ulong
ItemLocations.ClearAll()

Remove every registered override, restoring loaded nodes.

ItemLocations.OnLooted

Fires on the main thread when any item location is actually looted: (location id, slot index, item taken). Slot is -1 when the game looted without a specific slot (e.g. "take all" / auto-fit paths). This is the "check" signal for randomizers.

ItemSlot

ItemSlot.Root

The cell's GameObject.

ItemSlot.Rect

The cell's RectTransform (size it, or let a layout group drive it).

ItemSlot.Selectable

The cell's uGUI Selectable — compose into navigation chains (ItemGrid does).

ItemSlot.AuthoredSize

The cell's authored (prefab) size — the native footprint layout containers should honor.

ItemSlot.Create(parent, item, count?, onConfirm?)

Create a native item cell under parent showing item. Hover selects; click / gamepad Submit fires onConfirm. Returns null when the native slot template isn't available (the game UI hasn't loaded).

parent RectTransform
item InventoryItemStringIdEnum
count opt int
onConfirm opt Action
ItemSlot.SetItem(item, count?)

Re-bind the cell to another item/count (the slot's own native Setup path).

item InventoryItemStringIdEnum
count opt int
ItemSlot.Select()

Move uGUI selection to this cell (fires the authored selection feedback).

ItemSlot.SetVisible(visible)

Show/hide the cell without destroying it (the slot's native ToggleDisplay).

visible bool
ItemSlot.Destroy()

Tear the cell down. Safe to call more than once.

Items

Read-only catalog of every item in the game.

Items.All IReadOnlyList

Every item in the game (315 entries). Cached after first access.

Items.Get(id) InventoryItem

Resolve a single item config by enum id.

id InventoryItemStringIdEnum The item's enum identifier.
Example
foreach (var info in Items.All)
    Log($"{info.Name}  {info.StoredIn}  {info.UnitWeight:F2}kg");

var rope = Items.Get(InventoryItemStringIdEnum.Rope_Standard);

Label

A text label in the game's own font. Prefer this over Ui.Label (a plain fallback font) for any text a player will see.

Label.Root

The label's GameObject.

Label.Rect

The RectTransform (sized by its parent layout or by you).

Label.Tmp

The underlying TextMeshPro component, for advanced styling.

Label.GameFont

The game's own TMP font asset; null until the game UI has loaded.

Label.Create(parent, text, fontSize?, color?, alignment?)

Create a native-font label under parent. Fills the parent by default — re-anchor Label.Rect or let a layout group drive it. Returns null on failure (game UI not loaded yet).

parent RectTransform Where to attach.
text string Initial text.
fontSize opt float Point size (native menus use 26–38; headers up to 51).
color opt Color? Text color; null = white (the native default).
alignment opt TextAlignmentOptions? TMP alignment; null = centered.
Label.SetText(text)

Change the text.

text string
Label.SetColor(color)

Change the text color.

color Color
Label.Destroy()

Tear the label down. Safe to call more than once.

Lamp

The local player's lamp (the glowing light stick). Its state is a three-way mode, not a bool: Auto (the game decides by darkness), ForceOn, ForceOff. Reads return null and writes return false when no pawn is up yet.

Lamp.Mode

The local player's lamp mode, or null when no pawn is up.

Lamp.SetMode(mode)

Set the local player's lamp mode through the lamp's own verb (visuals update immediately). Returns false when no pawn is up.

mode AavaLightStick.Mode

LevelDescriptor.LevelKind

LevelDescriptor.LevelKind.GameWorld

LevelDescriptor.LevelKind.Custom

LevelLoader

LevelLoader.CustomSessionLive

A custom-level session is live — traveling into a custom level or its scene is resident.

LevelLoader.LaunchNonce

Per-launch identity of the last MOD-INITIATED custom launch (the custom analog of Session.LaunchGuid). LevelLoader.CreateAndPlay's custom branch mints a fresh one at launch-fire; the launching mod captures it and compares on arrival to prove the gameplay that arrived is the launch it fired. CustomSessionLive alone is a CLASS check — a native Continue of a custom save arms the same session machinery — so the nonce narrows arrival to OUR launch. What keeps it honest: every save-READ while a launch is pending stands the whole launch down (SaveLoadCustomPatch — a mod launch never reads a save), so no Continue variant can be adopted; and quit-to-menu stands it down at residency end (OnSceneUnloaded), so nothing armed persists at the menu. The ONE remaining window: a player-initiated NEW GAME inside the wedge window (≤30s, the watchdog's bound) reads no save and resolves through the same armed new-game redirect — indistinguishable from our launch at the resolver — and is adopted.

Limbs

The local climber's four limbs — resolution, state reads, and actions. Everything resolves through PawnManager.ClimbingPawnController, the same active-controller handle the game's own limb-selection HUD drives, so Limbs.LocalController is always the LOCAL pawn even in co-op (each remote ghost has its own controller and four limbs, which this never touches). All members are null-safe: they return null / false when there is no climbing session. Limbs are addressed by identity — IKLimbTarget (LeftHand / RightHand / LeftFoot / RightFoot), a ctor-set readonly enum on each limb that never drifts — via the controller's named-field accessors, the stable interop surface.

Limbs.LocalController

The local player's active climbing controller, or null when not climbing. This is the game's own PawnManager.ClimbingPawnController: the local pawn, never a co-op ghost.

Limbs.LeftHand

The local left-hand limb, or null when not climbing.

Limbs.RightHand

The local right-hand limb, or null when not climbing.

Limbs.LeftFoot

The local left-foot limb, or null when not climbing.

Limbs.RightFoot

The local right-foot limb, or null when not climbing.

Limbs.Get(target) ClimbingV2PawnLimb, or null.

The local limb for a given target, or null when not climbing.

target ClimbingPawnCairnIK.IKLimbTarget Which limb — LeftHand, RightHand, LeftFoot, or RightFoot.
Limbs.All IReadOnlyList

All four local limbs, in LeftHand, RightHand, LeftFoot, RightFoot order, skipping any that are null. Empty when not climbing.

Limbs.OppositeOf(limb) The opposite ClimbingV2PawnLimb, or null.

The same-kind opposite of a limb (left↔right within hand, or within foot), or null. Useful for auto-pickers that must never hand back the passed limb.

limb ClimbingV2PawnLimb The limb to mirror.
Limbs.IsHolding(limb) True if holding.

True when the limb is gripping a hold (state == Holding). This is the game's load-bearing signal: the effort/stamina economy and every "is attached" predicate key on it.

limb ClimbingV2PawnLimb The limb to test.
Limbs.IsActive(limb) True if the limb is engaged rather than idle.

True when the limb is in any active climbing state — reaching, holding, or moving to a hold (including the ice-climbing variants) — as opposed to Idle.

limb ClimbingV2PawnLimb The limb to test.
Limbs.GrabNearbyHolds() True if the grab was issued.

Snap every idle/reaching limb onto the nearest reachable hold — the game's own ForceAllReachingAndIdleLimbsToGrab. Used to attach the climber to the wall after a bare climbing placement (a route start with no captured pose): the pawn arrives in climbing mode with limbs dangling, and this grabs the holds around them. No-op (returns false) when not climbing.

Limbs.Drop(limb) True if a drop was issued.

Force the limb to let go through the game's own Drop path — clears its current grab and routes it back to Idle. Local pawn only. No-op (returns false) if the limb is null.

limb ClimbingV2PawnLimb The limb to release.

Localization

Localization.Register(english)

Register english under English and hand back a loc key that renders it in EVERY language (English is the fallback for all). For plain or user-generated content (names, labels) that is not translated. Write the returned key wherever the game wants a LocKeyStringId and the game's own text pipeline renders this string there, durably.

english string
Localization.Register(byLanguage)

Register a full per-language table and hand back a loc key. Language codes are upper-normalized (so "en" and "EN" are the same entry). The English entry is the fallback for any language not in the table; if the table has no English entry the first entry is used as the fallback.

byLanguage IDictionary<string, string>
Localization.Update(key, english)

Replace the English / fallback text of a key returned by Localization.Register.

key LocKeyStringId
english string
Localization.Update(key, lang, text)

Set or replace the text for one language of a registered key (language code upper-normalized). A key not registered here is ignored.

key LocKeyStringId
lang string
text string
Localization.Unregister(key)

Drop a registered key; the game falls back to its own resolution for that id afterward.

key LocKeyStringId
Localization.IsRegistered(key)

True if key is one this facade resolves.

key LocKeyStringId

LucideIcons

Built-in Lucide icon set (1964 icons), embedded as an indexed PNG blob and decoded to sprites on demand. Mods reference an icon by its Lucide name (e.g. "anchor", "flame", "mountain-snow"). Icons are white line-art on transparent — they tint cleanly over the menu's coloured wedge backgrounds. Pack format (little-endian): u32 count, then count × (u16 nameLen, name UTF-8, u32 dataLen) index, then the concatenated PNG bytes in index order.

LucideIcons.Names

All available Lucide icon names (loads the index on first call).

LucideIcons.Has(name)

True if the named icon exists in the bundle.

name string
LucideIcons.Get(name)

Get the sprite for a Lucide icon name, decoding + caching on first use. Returns null if the name is unknown (caller falls back to a placeholder).

name string

Meter

The game's segmented stat bar (the character-menu vitals meter) as a mod widget.

Meter.Root

The meter's GameObject.

Meter.Rect

The RectTransform (authored size 361×31; resize or let a layout group drive it).

Meter.Create(parent)

Create a native stat bar under parent. Returns null on failure (game UI not loaded yet).

parent RectTransform
Meter.Set(fill, preview?, low?, critical?)

Set the meter. fill and preview are 0–1; preview shows a pending change (defaults to the fill value); low tints the fill, critical plays the critical state.

fill float
preview opt float
low opt bool
critical opt bool
Meter.Destroy()

Tear the meter down. Safe to call more than once.

Example
var m = Meter.Create(hud.Content);
m.Set(0.75f);                          // value
m.Set(0.35f, low: true);               // low-state tint
m.Set(0.10f, critical: true);          // critical blink

NewGame

Programmatic new-game launch: start a fresh story-mode game (creating a new save) without walking the native menu screens. The exact endpoint the game's own New Game flow reaches — the difficulty/tutorial choices its screens collect are passed in instead.

NewGame.LaunchStory(difficulty, character?, skipTutorials?, skipPractice?)

Launch a new story-mode game with the given difficulty and character, optionally skipping the tutorials and the practice wall. Returns a status string ("STORY_LAUNCH_INVOKED" on success); fire-and-return — the load runs natively.

difficulty DifficultyTweakables.SelectedDifficulty
character opt PawnManager.Character
skipTutorials opt bool
skipPractice opt bool

Outfit

The player's outfit (body + clothes skin). Outfits are authored PawnSkinData assets keyed by a small enum (PawnBodyAndOutfitSkinType: Default / IceClimbing / Pajamas / NoHood) in the pawn's skin database; applying one swaps meshes and materials on the character's renderers with bones rebound BY NAME — which makes the applier rig-portable: Outfit.ApplyToRig can dress any Aava-skeleton rig (the netplay ghost included), not just the local pawn. Reads return null and writes return false when no pawn is up.

Outfit.Current

The local player's current outfit, or null when no pawn is up.

Outfit.Set(type)

Switch the local player's outfit through the pawn's own verb (meshes and materials swap immediately). Returns false when no pawn is up, the type is unknown to the skin database, or the outfit is already current.

type PawnBodyAndOutfitSkinType
Outfit.ApplyToRig(type, skeletonRoot, bodyRenderer, outfitRenderer)

Dress an arbitrary Aava-skeleton rig in type: the outfit's authored mesh, materials and bounds are copied onto the given body/outfit renderers with bones rebound by name against skeletonRoot's hierarchy — the game's own cross-rig skin worker. The skin data comes from the LOCAL pawn's skin database (always populated in gameplay). Returns false when no pawn is up or the type is unknown.

type PawnBodyAndOutfitSkinType
skeletonRoot Transform
bodyRenderer SkinnedMeshRenderer
outfitRenderer SkinnedMeshRenderer

Panel

A container panel wearing the game's own authored chrome (see CairnAPI.PanelStyle). Build content under Panel.Content — it is inset past the chrome's drawn border.

Panel.Root

The panel's GameObject.

Panel.Rect

The panel's RectTransform (fills the parent by default; re-anchor or resize freely).

Panel.Content

The content region, inset past the chrome's drawn border — build inside this.

Panel.Create(parent, style?, hat?)

Create a native-chromed panel under parent. Fills the parent by default — re-anchor Panel.Rect or let a layout group drive it. Returns null on failure (game UI not loaded yet).

parent RectTransform Where to attach.
style opt PanelStyle Which authored skin.
hat opt bool Dialog only: also add the authored top-center crest decoration.
Panel.Destroy()

Tear the panel down. Safe to call more than once.

PanelStyle

The authored chrome skins a CairnAPI.Panel can wear.

PanelStyle.Dialog

The cream dialog-box background the game's popups use.

PanelStyle.Outline

The border-only frame the in-game goals list uses.

PawnPose

A verbatim snapshot of the local climber's stance: locomotion mode, body/root world transforms, and all four limbs. Captured with Poses.TryCapture, re-applied with Poses.Restore. Pure floats and hold ids — embeds directly in JSON stores (bookmarks, route markers).

PawnPose.Mode

Locomotion mode at capture (PawnControllerSwitcher.Mode; 2 = Climbing).

PawnPose.Body

Body world transform, packed [px,py,pz, rx,ry,rz,rw].

PawnPose.Root

Root-node world transform, packed [px,py,pz, rx,ry,rz,rw].

PawnPose.LeftHand

The left-hand limb snapshot.

PawnPose.RightHand

The right-hand limb snapshot.

PawnPose.LeftFoot

The left-foot limb snapshot.

PawnPose.RightFoot

The right-foot limb snapshot.

PawnPose.OnWall

True when this pose was captured on the wall (climbing mode).

PawnPoseLimb

One limb of a captured pose: attachment state, IK end bone, grab anchor, and the hold it was on (for drift detection at restore). Pure floats — JSON-serializable, no scene references.

PawnPoseLimb.State

The limb's attachment state (ClimbingV2PawnLimb.LimbState; 2 = on a hold).

PawnPoseLimb.End

IK end-bone world transform, packed [px,py,pz, rx,ry,rz,rw].

PawnPoseLimb.Anchor

Grab-anchor world transform, packed [px,py,pz, rx,ry,rz,rw].

PawnPoseLimb.Bend

IK bend-goal world position [x,y,z].

PawnPoseLimb.SubBone

Local sub-bone rotation (foot ball bone) [x,y,z,w].

PawnPoseLimb.HoldId

Persistent id of the hold the limb was on, or 0 when unattached.

PawnPoseLimb.Attached

True when this limb was captured gripping a hold.

PillButton

A filled pill button — the style the game's dialog options and bivouac actions use.

PillButton.Root

The button's GameObject.

PillButton.Rect

The RectTransform (authored footprint 200×50; resize or let a layout group drive it).

PillButton.Selectable

The underlying uGUI Selectable, for navigation wiring.

PillButton.Create(parent, label, onClick, glyphAction?)

Create a pill button under parent. Click / Submit fires onClick. Returns null on failure (game UI not loaded yet).

parent RectTransform Where to attach.
label string Button text.
onClick Action Fired on click / Submit.
glyphAction opt InputAction Optional input action whose keycap renders inside the left edge (see CairnAPI.Glyph).
PillButton.Create(parent, label, onClick, icon)

Create a pill button with a sprite icon (e.g. ItemInfo.Icon) inside the left edge.

parent RectTransform
label string
onClick Action
icon Sprite
PillButton.SetLabel(text)

Change the label text.

text string
PillButton.SetInteractable(interactable)

Enable/disable interaction (native disabled tint).

interactable bool
PillButton.Select()

Move uGUI selection to this button.

PillButton.Destroy()

Tear the button down. Safe to call more than once.

Example
var b = PillButton.Create(panel.Content, "Consume", OnConsume, Glyph.Action(GameAction.Confirm));

PoseCaptureStatus

Outcome of a capture attempt — see Poses.TryCapture.

PoseCaptureStatus.Refused

Capture refused: the climber is mid-move (reaching, mantling, on the rope), off every wall hold, in a transitional state, or absent.

PoseCaptureStatus.Grounded

The climber is standing on the ground — a valid spot, but there is no wall pose to store (ground placement needs only a position).

PoseCaptureStatus.OnWall

The climber is in a stable climbing stance — a verbatim pose was captured.

PoseCaptureStatus.Falling

The climber is falling — nothing meaningful to capture.

Poses

Capture and restore the local climber's verbatim pose. A captured CairnAPI.PawnPose stores the exact stance — body position and which limbs grip which holds, where — so a route or bookmark can put the climber back into it (one-arm hangs included). Restore places the body immediately through the game's own state restore, then tightens each limb to its exact recorded anchor over the following frames; where the world no longer supports an anchor, the game's own nearby pick stays and the approximation is logged once.

Poses.TryCapture(pose, reason)

Capture the local climber's current stance. PoseCaptureStatus.OnWall fills pose with the verbatim on-wall pose (body + all four limbs); PoseCaptureStatus.Grounded also fills pose, with just the body position/rotation (no limbs — standing on the ground has nothing else to capture, but the facing is still worth restoring verbatim rather than losing it to a bare position); PoseCaptureStatus.Refused and PoseCaptureStatus.Falling leave pose null and set reason (a limb mid-move, on the rope, no wall hold gripped, falling, no climber).

pose PawnPose
reason string
Poses.CanCapture()

True when a capture would succeed right now: standing on the ground, or a stable climbing stance (steady on the wall with at least one limb on a real hold). False while falling, reaching, mantling, or on the rope — use it to gate capture verbs live.

Poses.Restoring

True while a restore's per-limb pass is still running.

Prompt

Ask the player to type something: message, input line, confirm/cancel buttons, in the game's dialog chrome. Enter or the confirm button submits; cancel (or a replacing Show) discards. Keyboard-first — gamepads can press the buttons but have no on-screen keyboard.

Prompt.Show(message, onSubmit, confirmLabel?, cancelLabel?, initial?, onClosed?)

Show the prompt. Returns false when the game UI isn't loaded yet.

message string The question, centered over the input line.
onSubmit Action<string> Receives the typed text (may be empty) on confirm/Enter.
confirmLabel opt string
cancelLabel opt string
initial opt string
onClosed opt Action Fires exactly once when the prompt's UI is torn down, for ANY reason — confirm, cancel, Esc/B under the modal, or a replacing Prompt.Show. On the confirm path it fires as part of the close, just before onSubmit runs.
Prompt.Close()

Dismiss the open prompt, if any (no submit).

Prompt.IsOpen

Whether a prompt is currently on screen.

ProximityInteractable

The MonoBehaviour behind ProximityPrompt.Show. Polls Aava's distance to the anchor each frame: in range → shows a CairnAPI.WorldPrompt; out of range → hides it; pressing the glyph button while in range fires the callback.

ProximityInteractable.Destroy()

Remove this prompt and its GameObject.

ProximityPrompt

ProximityPrompt.Show(anchor, distance, text, glyph?, onInteract?)

Show a CairnAPI.WorldPrompt over anchor while Aava is within distance of it. onInteract fires on the glyph's button while in range. Returns the component; call ProximityInteractable.Destroy to remove it.

anchor Transform
distance float
text string
glyph opt InputAction
onInteract opt Action

ReachInteractable

The MonoBehaviour behind ReachPrompt.Show / ReachPrompt.Create. Trigger-driven: a limb sensor reaching into our collider shows a CairnAPI.WorldPrompt; leaving hides it; pressing the glyph button while reaching fires the callback.

ReachInteractable.Destroy()

Remove this prompt and its GameObject.

ReachPrompt

ReachPrompt.Show(anchor, text, glyph?, onInteract?, radius?, localOffset?, hands?)

Attach a reach prompt to a MOVING anchor (e.g. the climbot, an NPC, a carried prop). Parented to the anchor, so it tracks it automatically — pass the transform of the thing the player reaches toward. Shows a CairnAPI.WorldPrompt with text + glyph while a limb is REACHING into radius; onInteract fires on the glyph's button while reaching. localOffset shifts the trigger from the anchor's pivot to the actual grab point. hands true = only hands trigger it; false = any limb.

anchor Transform
text string
glyph opt InputAction
onInteract opt Action
radius opt float
localOffset opt Vector3
hands opt bool
ReachPrompt.Create(position, text, glyph?, onInteract?, radius?, hands?)

Spawn a reach prompt at a FIXED world position (a lever, a wall panel — something that doesn't move). For anything that moves, use ReachPrompt.Show instead.

position Vector3
text string
glyph opt InputAction
onInteract opt Action
radius opt float
hands opt bool

RoutingHandler

The single Il2Cpp-injected UI.CrossMenuActionHandler subclass. The game's CrossMenuUI stores one handler per CrossMenuActionType in its handlers dictionary and dispatches OnExecute/IsAvailable/ GetCount through the native vtable. We register ONE managed subclass and give each instance a synthetic type-int; the virtual overrides route to the managed CairnAPI.Registry by that int, so consumer mods never touch Il2Cpp. This is the load-bearing assumption of the whole library: that a native vtable call into the game's handler dict reaches these managed overrides. Proven shaped-correct live (base exposes an (IntPtr) injectable ctor and OnExecute is virtual); end-to-end dispatch is exercised by the in-game smoke test.

RoutingHandler.TypeValue

The synthetic CrossMenuActionType int this instance answers for. Set right after construction (managed-side field; not visible to Il2Cpp, which is fine — only our overrides read it).

SaveSlotList

SaveSlotList.Root

The list's root GameObject.

SaveSlotList.Create(parent, onPick, filter?)

Build a native save-slot list under parent from the game's cached Story-save previews (title-screen context — the same source the native save select reads). onPick fires with the row index and its preview on click / Submit. filter (optional) keeps only matching previews. Returns null when no previews are cached (not at the title screen yet) or the row template is unavailable.

parent RectTransform
onPick Action<int, SavegameManager.SavePreviewInfo>
filter opt Func<SavegameManager.SavePreviewInfo, bool>
SaveSlotList.Count

Number of rows.

SaveSlotList.FocusFirst()

Focus the first row (gamepad/keyboard nav anchors here).

SaveSlotList.Destroy()

Tear the list down. Safe to call more than once.

Screen

Screen.GameState

GlobalGameManager.GameState enum value at the top of the state stack.

Screen.IsMenu

The main menu system is active (GameState stack contains Menu).

Screen.IsInGame

Gameplay is active (GameState stack contains InGame). This is true even when the pause menu or bivouac is on top.

Screen.IsCutscene

A cutscene is playing (GameState stack contains Cutscene).

Screen.IsGameOver

The game-over screen is up (GameState stack contains GameOver).

Screen.IsBivouac

The bivouac rest menu is active (GameState == Bivouac).

Screen.PawnSpawned

The pawn (Aava) is spawned in the world — the real "we are in live gameplay" test. Unlike LoadingState.GameStarted this is not sticky across menu returns.

Screen.LoadingState

The game's detailed load pipeline stage. ⚠ Sticky: retains its last value (e.g. GameStarted=8) after returning to the menu. The authoritative "fully in gameplay" signal is PawnSpawned, not GameStarted.

Screen.IsTransitioning

A cross-world / cross-zone / menu scene transition is in flight.

Screen.IsLoadingMenu

Specifically a game→menu transition is in flight (subset of IsTransitioning).

Screen.CurrentMenu

The foremost open Menu canvas, or null. Changes only at UIManager.OnMenuClosed / OnMenuStacked — observe via OnMenuChanged if you need a callback.

Screen.OnGameStateChanged

Fires whenever GlobalGameManager.GameState changes. Arguments: (from, to). Sourced from GameEventManager.ChangeGameState — fires for every push/pop and direct set.

Screen.OnMenuChanged

Fires when UIManager.CurrentMenu changes (a menu opens or the foreground menu closes). Argument is the NEW current menu (null when the stack empties).

Screen.OnCanvasOpened

Fires when any BasicCanvasHandlerBehaviour finishes opening (OnOpened). Fires for menus AND HUDs. Cast the argument to check the concrete type.

Screen.OnCanvasClosed

Fires when any BasicCanvasHandlerBehaviour finishes closing (OnClosed). Fires for menus AND HUDs. Cast the argument to check the concrete type.

Screen.OnTransitionStarted

Fires when a game→menu or menu→game scene transition starts. Sourced from CairnSceneManager.OnGameUnloadingAboutToStart.

Screen.OnTransitionCompleted

Fires when a scene transition completes and all new scenes are ready. Sourced from CairnSceneManager.OnGameScenesReady.

Screen.OnEnteringMenu

Fires specifically when entering the main menu scene (game→menu path only), just before the menu scene itself loads. CairnSceneManager.OnPreparingToLoadMenu.

ScreenPrompt

ScreenPrompt.Show(text, glyph?, parent?)

Show a screen-space prompt. text is shown as-is, glyph is the button icon (see CairnAPI.Glyph, null = none). If parent is null the row goes under a mod-owned overlay Canvas — place it with ScreenPrompt.Move; if given, the row is parented there (self-sizes for a HorizontalLayoutGroup). Returns a handle, or ScreenPromptHandle.Invalid if a required game asset isn't loaded yet.

text string
glyph opt InputAction
parent opt Transform
ScreenPrompt.Move(handle, anchoredPos)

Place an own-Canvas prompt anywhere on screen (its RectTransform's anchoredPosition). No-op for a prompt parented into your own layout (let the layout group place it).

handle ScreenPromptHandle
anchoredPos Vector2
ScreenPrompt.SetText(handle, text)

Change a live prompt's text in place (set once; persists with no pump).

handle ScreenPromptHandle
text string
ScreenPrompt.SetActive(handle, active)

Show / hide the prompt (a layout group re-flows around a hidden one). Cheap — no re-register.

handle ScreenPromptHandle
active bool
ScreenPrompt.Hide(handle)

Destroy the prompt. Safe on an invalid handle.

handle ScreenPromptHandle

ScreenPromptHandle

Opaque handle to a shown CairnAPI.ScreenPrompt. Pass it back to ScreenPrompt.Hide.

ScreenPromptHandle.Invalid

A no-op handle returned when a required asset / the HUD wasn't available.

ScreenPromptHandle.SetActive(active)

Show / hide the prompt (the layout group re-flows around a hidden one).

active bool
ScreenPromptHandle.Destroy()

Destroy the prompt GameObject. Idempotent; on an already-dead row it just invalidates.

ScrollList.KeyAction

A global keybind acting on the selected row — the same cross-device InputSystem.InputAction (build one with Glyph.Custom) both renders the prompt-strip glyph and, polled, fires the verb. See ScrollList.SetKeyActions.

ScrollList.KeyAction.Label

Prompt-strip label (e.g. "Rename").

ScrollList.KeyAction.Action

Cross-device action — glyph AND trigger.

ScrollList.KeyAction.OnPerformed

Runs with the selected row index when the action fires.

ScrollList.KeyAction.EnabledFor

Per-row gate; null = every row. Returning false hides the strip prompt and swallows the key on that row.

ScrollList.Row

One row: its label plus optional trailing action pills rendered inside the row's right edge. A row with actions treats click/Submit as "focus my first pill" (the verbs live there); a plain row fires the list's onConfirm.

ScrollList.Row.Value

Right-aligned dim metadata column (e.g. a best time); null = none. Ignored on a row with Row.Actions — a pill tray owns the right edge.

ScrollList.RowAction

A trailing pill on a ScrollList.Row (native pill chrome, disabled tint when off).

ScrollList

A scrollable, selectable list of text rows in the game's own visual language — each row is the native free-roam warp-point row (ordinal + label + selection band), Instantiated from the game's prefab and driven through its own bind method, hosted in a masked scroll view that auto-follows the selection. Handle-object: ScrollList.Create builds it under a parent (e.g. a MenuScreen.AddWidgetPage content area), ScrollList.Destroy tears it down. Rows navigate with the native Selectable chain (keyboard/gamepad), select on hover, and fire onConfirm(index) on click or Submit.

ScrollList.Create(parent, items, onConfirm)

Build a scroll list filling parent. items are the row labels; onConfirm receives the row index on click or Submit. Rows are always the game's own warp-list rows: read from memory when their bundle is loaded (any gameplay context), else the owning prefab is asset-loaded through the game's Addressables (works on the title screen too).

parent RectTransform
items IReadOnlyList<string>
onConfirm Action<int>
ScrollList.Create(parent, items, onConfirm?)

Build a scroll list of ScrollList.Rows — labels with optional trailing action pills.

parent RectTransform
items IReadOnlyList<ScrollList.Row>
onConfirm opt Action<int>
ScrollList.Valid

True once built and still alive.

ScrollList.Cursor

Index of the currently-selected row, or -1 when none of ours is selected.

ScrollList.SetItems(items)

Replace the row labels. Rows are rebuilt to the new count; loc keys are reused per slot so repeated refreshes (e.g. a lobby list poll) don't grow the localization registry.

items IReadOnlyList<string>
ScrollList.SetItems(items)

Replace the rows (labels + trailing action pills). Same slot-key reuse as the string form.

items IReadOnlyList<ScrollList.Row>
ScrollList.Count

Number of rows currently shown.

ScrollList.TopRow

The current top (first) row's Selectable (null when empty) — for wiring an outside widget's down-navigation INTO the list (so descending from a control above lands on the list, not past it).

ScrollList.BottomRow

The current bottom row's Selectable (null when empty) — for wiring an outside widget's up-navigation back into the list.

ScrollList.SetNavigationOutside(before, after)

Wire the list's outside neighbours. before = the control above/left (selectOnLeft on every row, selectOnUp on the first row); after = the control below/right (selectOnRight on pill-less rows — on pill rows the last pill's selectOnRight — plus selectOnDown on the last row). Null = that edge stays dead. Persisted — ScrollList.SetItems row rebuilds re-apply it.

before Selectable
after Selectable
ScrollList.SetKeyActions(actions)

Selected-row keybinds with a bottom glyph-prompt strip. Each ScrollList.KeyAction is polled while a row is selected (no modal up, no focused text field): the first enabled action whose cross-device KeyAction.Action fired this frame runs KeyAction.OnPerformed with the row index — one per frame. The strip shows one glyph+label per action (hidden per-row by KeyAction.EnabledFor) and follows selection. Persisted across ScrollList.SetItems; null/empty clears.

actions ScrollList.KeyAction[]
ScrollList.SetConfirmPrompt(label)

Add a display-only prompt to the strip for the game's Confirm action (Submit = go). Null removes it.

label string
ScrollList.SetPromptHost(host)

Render the keybind prompt strip inside host — a layout band the consumer owns (e.g. below the list frame) — instead of a reserved band inset into the list's own viewport. Null returns it to the in-list band. A live strip relocates. Set this before ScrollList.SetKeyActions for no churn.

host RectTransform
ScrollList.Select(index)

Move UI focus to a row by index (clamped; no-op when empty).

index int
ScrollList.FocusFirst()

Focus the first row (the CairnAPI.IMenuWidget page-open hook).

ScrollList.Destroy()

Tear the list down and invalidate the handle. Safe to call more than once.

ScrollList.Tick()

Per-frame pump for every live list's keybind polling + prompt strip — call once from OnUpdate.

Session

The mod-launched gameplay-session lifecycle. A mod that launches its own session (summit run, custom level) arms this at launch-fire with Session.Begin; the session ends when the game is back at the title menu. Consumers gate session-scoped surfaces (pause entries, verbs, world mutations) on Session.Active/Session.Owner and reset per-session state from Session.Ended.

Session.Active

A mod-launched session is live (armed at launch, cleared at the title menu).

Session.Owner

The mod that launched the active session, or null.

Session.Ephemeral

The active session is save-less: while it runs (pawn spawned), every save the game attempts is refused through the game's own CanSave gate — no save file is created or touched, and the player's save list is unaffected. Armed only by the ephemeral launch surface (LevelLoader.PlayEphemeral); cleared when the session ends.

Session.LaunchGuid

Identity of the GameSetup the owning launch planted (its freshly-minted guid), for arrival verification: compare against GameSetup.GetCurrentGameSetup().guid once gameplay is up to prove the arrived session is the launched one. Null for launches without a planted setup.

Session.Ended

Raised once when the active session ends (title menu reached, or the early menu-transition signal). Subscribers are isolated: one throwing handler cannot starve the others.

Session.ReachedGameplay

The session has reached gameplay (pawn spawned at least once since launch). Latched — stays true through in-session despawn windows (retry reloads, travel) until the session ends.

Session.CurrentSetupGuid()

The guid of the live session's GameSetup (every setup ctor mints a fresh one — a per-launch identity), or null while unreadable / still all-zeros. Compare with Session.LaunchGuid.

Session.Begin(owner)

Arm the session at launch-fire time — call immediately after the launch mechanism has actually been invoked, before gameplay arrives.

owner string
Session.Cancel(reason)

End the active session from the owning mod's side — for when the owner determines the gameplay that arrived is not the session it launched (identity check failed). Raises Session.Ended exactly like a natural end.

reason string

SettingsPage

SettingsPage.Refresh()

Re-run the page builder and show the result without leaving the page.

SettingsPage.SetFields(fields)

Replace the page's visible rows with fields without leaving the page. Safe to call from inside a field callback — the swap is deferred to the next frame so the row that raised the event is not torn down mid-dispatch.

fields Field[]
SettingsPage.Dispose()

Remove the rail entry. Pages normally live for the mod's lifetime.

Stamina

Stamina.AddEffortScale(key, scale)

Register (or replace) a global effort cost multiplier. Applied uniformly to all limbs via CurrentEffortCostMultiplier. 1.0 = no effect.

key string
scale float
Stamina.RemoveEffortScale(key)

Remove a registered global effort scale.

key string
Stamina.AddEffortScaleProvider(key, provider)

Register (or replace) a per-limb effort scale provider. Callback receives the limb and returns a multiplier for that limb's CurrentEffortCostMultiplier. 1.0 = no effect.

key string
provider Func<ClimbingV2PawnLimb, float>
Stamina.RemoveEffortScaleProvider(key)

Remove a registered per-limb effort scale provider.

key string
Stamina.AddDrainScale(key, scale)

Register (or replace) a global drain speed multiplier. Applied to every limb's _CurrentStaminaConsumptionSpeed after UpdateStaminaState computes it. Only scales positive (draining) values; gaining limbs are not affected. 1.0 = no effect.

key string
scale float
Stamina.RemoveDrainScale(key)

Remove a registered global drain scale.

key string
Stamina.AddDrainScaleProvider(key, provider)

Register (or replace) a per-limb drain speed scale provider. Callback receives the limb and returns a multiplier for that limb's drain rate. Only applied when the limb is draining (consumptionSpeed > 0). 1.0 = no effect.

key string
provider Func<ClimbingV2PawnLimb, float>
Stamina.RemoveDrainScaleProvider(key)

Remove a registered per-limb drain scale provider.

key string
Stamina.Package

The live ClimbingTweakablesPackage.Stamina for the local pawn. Fields: baseStamina, staminaGainSpeed, staminaLossSpeed, staminaLossCurve, criticalStaminaStateDuration, punishedCriticalStaminaStateDuration, effortExhaustionThreshold, handRestThreshold, footRestThreshold, handFreeEffortThreshold, footFreeEffortThreshold. Null if not in a session or the package isn't loaded.

Stance

Where AND how the pawn stands: a world position + facing + locomotion mode, or a verbatim captured pose (CairnAPI.PawnPose — on-wall stances), or the level's default spawn (Stance.Spawn). This is the destination TYPE handed to Teleport.To and Travel.To; placement itself is owned by the teleport pipeline (session gate → zone-ensure → readiness → place → arrive), never applied directly by callers.

Stance.Position

Target world position (ignored when Stance.Pose is set — the pose carries its own).

Stance.Facing

World forward to face on arrival; degenerate values fall back to +Z.

Stance.Mode

Locomotion mode to arrive in (Walking / Climbing).

Stance.Pose

Verbatim stance (a CairnAPI.Poses capture). When set, the pose restore owns placement.

Stance.Spawn

The level's default spawn — where THIS session's pawn first spawned, placed through the game's own spawner verb (mode, on-wall start, climbbot handling reproduced natively). A shared sentinel; do not mutate its fields.

Stance.IsSpawn

True when this is the Stance.Spawn sentinel.

Stance.TargetPosition

Where this stance puts the pawn (a pose carries its own body position; the spawn sentinel resolves to the session's default spawn).

TabBar

TabBar.Root

The rail's root GameObject (a vertical column; size it via its RectTransform).

TabBar.Create(parent, labels, onPicked, onSelected?)

Build a native selection rail under parent with one entry per label. onPicked fires with the entry index on click / gamepad Submit. onSelected (optional) fires when the highlight moves (hover / gamepad nav). Returns null when the game UI isn't up yet (no chevron/highlight assets to decorate with).

parent RectTransform
labels IReadOnlyList<string>
onPicked Action<int>
onSelected opt Action<int>
TabBar.Valid

True once built and still alive.

TabBar.Select(index)

Move the native highlight (chevron + text slide) to an entry, as gamepad nav would.

index int
TabBar.FocusFirst()

Focus the first entry (gamepad/keyboard nav anchors here).

TabBar.SetActiveTab(index)

Pin an entry as the active tab (the picked-page look: highlight held while the selection roams). Picking an entry pins it automatically; -1 clears the pin.

index int
TabBar.ActiveTab

The pinned tab's index (-1 when none is pinned yet).

TabBar.Destroy()

Tear the rail down. Safe to call more than once.

Teleport

THE move-the-pawn-within-this-session verb. Applies a CairnAPI.Stance to the local climber through one frame-ticked pipeline: session gate (wait for the pawn if a load is in flight) → zone-ensure (stream the destination's own sector) → readiness (settle + on-wall holds) → place (the fall-safe switcher transition / pose restore / native spawner, never a raw transform write) → arrive. One job is pending at a time; a new call supersedes it, and the session ending cancels it. A same-zone ground teleport collapses synchronously — TeleportOptions.OnArrived runs before Teleport.To returns. Cross-LEVEL travel is Travel.To, which lands the new session and then hands the arrival to this same pipeline.

Teleport.Pending

A teleport (or a Travel launch riding this pipeline) is in flight.

Teleport.To(destination, opts?)

Move the local climber to destination. Returns "OK" once the job is issued (or completed synchronously), "NOT_IN_SESSION" when there is no world at all, "TRAVEL_IN_FLIGHT" when a cross-level launch owns the slot, or "NO_STANCE" for a null destination. Supersedes any pending plain teleport.

destination Stance
opts opt TeleportOptions
Teleport.Cancel()

Cancel the pending job without firing its arrival callback. Refuses (no-op) when a Travel launch owns the slot — symmetric with Teleport.To's refusal, so a session-scoped caller (a Boulderdash run teardown) can never destroy an in-flight cross-level launch and strand it. Travel / session teardown that legitimately abandons the journey goes through Teleport.CancelAny.

TeleportOptions

Options for Teleport.To.

TeleportOptions.Placement

When the stance is applied: TeleportPlacement.WhenReady (default) waits for the destination to settle (and, for an on-wall stance, for the holds to stream in) before placing; TeleportPlacement.Immediate places at once (for callers holding their own freeze) — but TeleportOptions.OnArrived still defers to readiness. Placement and arrival are separate edges.

TeleportOptions.BeforePlaced

Runs on the same frame, immediately before the stance applies — for callers that must prepare the world first (e.g. freeze time so an on-wall placement doesn't fall while the holds subscene is still streaming). The stance is NOT applied yet when it runs.

TeleportOptions.OnArrived

Runs when the destination is REAL: settled, and (for an on-wall stance) the holds have arrived. The stance is already applied when it fires.

TeleportOptions.OnFailed

Runs when placement fails: Stance.Apply reported failure twice (once retried on the next tick). The job is cancelled before this fires; TeleportOptions.OnArrived will NOT run. Callers holding their own freeze wire this to stand it down.

TeleportPlacement

Whether a CairnAPI.Teleport places the stance immediately or waits for the destination to be ready.

TeleportPlacement.WhenReady

Wait for the destination to settle (and its holds, on-wall) before placing.

TeleportPlacement.Immediate

Place at once, before readiness — for callers parking the pawn under their own freeze.

Toast

Show a message as one of the game's own corner toasts. In-game surface (GlobalUIs) — returns false when it isn't loaded (main menu very early, or no scene).

Toast.Show(text, icon?, background?, foreground?)

Queue a toast. Optional icon and background/foreground tints ride the native toast fields; omitted = the toast's authored defaults.

text string
icon opt Sprite
background opt Color?
foreground opt Color?

Travel

THE go-to-a-LEVEL verb, keyed by level + CairnAPI.Stance, valid from anywhere. Resolves "where is the player right now" itself so callers never branch on it: • already on the level (and no TravelOptions.Fresh) → hand off to Teleport.To in place (no reload, no loading screen), returns "SAME_MAP"; • else, an TravelSession.Ephemeral launch (default) → a NEW save-less session honoring difficulty/character, returns "FRESH_SESSION"; • else, a TravelSession.Preserve launch → native change-level travel with the session/save intact, returns "PRESERVE". A launch that lands hands its arrival to the SAME teleport pipeline (zone-ensure → readiness → place → arrive), so TravelOptions.BeforePlaced/TravelOptions.OnArrived fire from there. Returns the launch funnel's failure reason otherwise.

TravelOptions

Options for Travel.To. Difficulty/character/owner shape the NEW session an Ephemeral launch starts; a same-map hop and a Preserve launch ignore them.

TravelOptions.Arrival

Arrival stance; null = the level's default spawn.

TravelOptions.ArrivalZoneName

Zone known to own the arrival position, captured when it was recorded; lets a menu launch load the destination's own zone when live resolution is impossible (at the title menu no zone colliders are registered, so a position→zone probe always fails and falls back to the entry zone).

TravelOptions.Fresh

Force a NEW session even when already on the level (e.g. a mode/character change).

TravelOptions.Session

Whether the launch starts a fresh save-less session (TravelSession.Ephemeral, default) or preserves the running session and its save (TravelSession.Preserve).

TravelOptions.Difficulty

New-session difficulty (TravelSession.Ephemeral only).

TravelOptions.Character

New-session character (TravelSession.Ephemeral only).

TravelOptions.Owner

Session owner (Session.Owner of a launched ephemeral session).

TravelOptions.Placement

Placement timing handed to the arrival's teleport pipeline (see CairnAPI.TeleportPlacement).

TravelOptions.BeforePlaced

Fires right before the arrival stance is applied, on the same frame (e.g. freeze time so an on-wall start doesn't fall while the holds subscene is still streaming). Not applied yet when it runs.

TravelOptions.OnArrived

Runs once the pawn stands on the destination — same call for a same-map hop, after arrival + settle (+ on-wall holds) for a launch. The stance is already applied when it fires.

TravelOptions.OnFailed

Runs when the arrival placement fails (see TeleportOptions.OnFailed). The journey is cancelled before it fires; TravelOptions.OnArrived will NOT run.

TravelSession

Whether a CairnAPI.Travel launch starts a fresh save-less session or preserves the running one.

TravelSession.Ephemeral

A NEW save-less session: no save is created or touched, and it ends at the title menu.

TravelSession.Preserve

The running session and its save are kept — native change-level travel (a member warp, story progression), session and save intact.

VitalAxes

Survival axes a CairnAPI.Vitals freeze can cover. Combine flags for a subset; VitalAxes.All freezes everything.

VitalAxes.None

No axes.

VitalAxes.Hunger

Hunger decay.

VitalAxes.Thirst

Thirst decay.

VitalAxes.Cold

Cold decay.

VitalAxes.Hp

Hit points — over-time decay, damage (falls included), and any write that would lower HP.

VitalAxes.Exhaustion

Exhaustion buildup from climbing exertion.

VitalAxes.Stamina

Climbing limb stamina drain (regen is unaffected).

VitalAxes.All

Every axis.

Vitals

Freeze survival drain and stamina for the local pawn. Freezes are named so multiple mods coexist: an axis stays frozen while any registered key covers it, and the game's normal drain resumes when the last such key is removed.

Vitals.AddFreeze(key, axes?)

Register (or replace) a named freeze covering the given axes. Frozen stats stop draining and cannot be lowered (damage included); raising writes — eating, drinking, warming, healing — still apply.

key string
axes opt VitalAxes
Vitals.RemoveFreeze(key)

Remove a registered freeze. Axes no longer covered by any key thaw and the game's own drain multipliers are restored.

key string

WarpEntry

One destination a CairnAPI.IWarpSource contributes to the eagle-eye warp list: a named world position with an opaque payload the source recognizes on confirm/edit.

WarpEntry.Position

The destination's world position (where the pin sorts and where confirm places the pawn).

WarpEntry.Name

The row label shown in the eagle-eye list.

WarpEntry.Payload

The source's own object behind this entry (a Bookmark, a Route, …) — passed back on confirm/edit.

WarpSources

Materializes the ACTIVE CairnAPI.IWarpSource's destinations as live Cairn.FreeRoamWarpPoints in the eagle-eye list, and routes selection back to the owning source (bypassing the native warp). Mods register sources; a toggle cycles which one the list shows. The materialization lifecycle (register on gameplay load, re-anchor on zone change, stand down before a scene unload) is the proven bookmark pattern, source-agnostic here.

WarpSources.Register(source, primary?)

Register a warp source. Pass primary for the built-in default-active source (bookmarks) so it stays the active list regardless of mod load order; others append.

source IWarpSource
primary opt bool
WarpSources.Active

The active source (whose destinations the eagle-eye list currently shows), or null.

WarpSources.Count

How many sources are currently AVAILABLE (a toggle is meaningful only when > 1) — an unavailable source (routes outside a Boulderdash session) is invisible here.

WarpSources.NextLabel()

The label of the next AVAILABLE source WarpSources.Toggle would switch to, or null when fewer than two are available — for a "Show " prompt.

WarpSources.Toggle()

Cycle to the next AVAILABLE source and re-materialize its destinations. The open eagle-eye list re-pulls its rows via the Bookmarks.OnRegistryChanged subscription.

WarpSources.Invalidate()

Force a re-materialize of the active source's destinations (call after its entries change).

WarpSources.Refresh()

Immediately re-materialize the active source and tell an open list to re-pull — for in-view state flips (the native-entries toggle) where the player is looking at the list and a deferred settle would read as a dead keybind.

WarpSources.TryResolve(wp, source, entry)

Resolve a live warp point back to its owning source + entry, or false for a point that isn't one of ours (a native destination — let the native warp run).

wp FreeRoamWarpPoint
source IWarpSource
entry WarpEntry
WarpSources.LocKeyOf(payload)

The live loc key rendering a materialized entry's row (for in-view live-rename via Localization.Update), or default when it has no live point.

payload object
WarpSources.RefreshName(payload, newName)

Live-rename a materialized entry's row without a rebuild (matches by payload identity).

payload object
newName string
WarpSources.Despawn(payload)

Tear down one materialized entry: unregister, drop its loc key, destroy its GO.

payload object

Weather

The weather machine, read and driven through the game's own systems. Weather is a per-zone state machine: a forecast of WeatherZoneData.WeatherType states, each bundling rain/thunder/fog/clouds components and a duration. Some zones drive weather from an authored time table instead — there weather is a pure function of the game clock (Weather.IsTableDriven), so change the CairnAPI.Clock to change the sky and Weather.Set declines. All reads fail soft (Undefined / zero) when the weather system isn't up yet, e.g. on the title screen.

Weather.Current

The live weather state (forecast slot 0), or Undefined when no weather system is up.

Weather.Forecast

The forecast (slot 0 = live state, later slots = the barometer's future). Empty when unavailable.

Weather.RemainingSeconds

Seconds until the live weather state expires (counts down).

Weather.DurationSeconds

Total duration of the live weather state, in seconds.

Weather.IsTableDriven

Whether the current weather zone derives its weather from an authored time table instead of the forecast. In table zones weather is a pure function of the game clock — change the CairnAPI.Clock to change the sky; Weather.Set declines.

Weather.Changed

Raised when a weather state is applied (state changes, zone changes, save loads), with the new live WeatherZoneData.WeatherType.

Weather.Set(type)

Switch the live weather to type, resolved against the current zone's authored definitions and applied through the weather machine's own trigger — modules transition naturally and the forecast keeps advancing afterwards (nothing is latched). Returns false when the zone is table-driven, the zone can't express the type, or no weather system is up.

type WeatherZoneData.WeatherType
Weather.ApplySnapshot(types, remainingSeconds, durationSeconds)

Apply a full weather snapshot — forecast types plus the live state's countdown — the way the game's own save-load does: each type is resolved against the LOCAL current zone, the trigger fires only when the live state actually changed, and the timer/duration are restored last. This is the replication verb (CairnCoop's world sync rides it); Weather.Set is the one-shot flavor. Returns false when nothing could be applied (table zone, no weather system, or slot 0 unresolvable in this zone).

types WeatherZoneData.WeatherType[]
remainingSeconds float
durationSeconds float
Weather.Rain

The live state's rain component (None / Rain_Small / Rain_Heavy).

Weather.Thunder

The live state's thunder component (None / Thunder_Far / Thunder_Close).

Weather.Fog

The live state's fog component (None / Fog_InsideCloud).

Weather.Clouds

The live state's clouds component (None / Clouds_Small / Clouds_Heavy).

Weather.SnowIntensity

Live snow intensity, 0..1 (precipitation renders as snow at altitude/temperature).

Weather.SnowInsteadOfRain01

How far precipitation currently leans to snow instead of rain, 0..1.

Weather.ForcePrecipitation(mode)

Force precipitation to render as snow or rain regardless of altitude/temperature, or None to restore the game's own choice.

mode WeatherManager.SnowRainForceMode
Weather.WindForce

Live wind strength (the value gameplay and cloth react to).

Weather.WindGust

Live gust multiplier layered on Weather.WindForce.

Weather.WindDirection

Live wind direction (normalized, world-space).

Weather.BarometerScore

The barometer's current score, 0 (storm) .. 1 (clear) — what the in-game barometer shows.

Weather.ForceFog(opacity, expOffset?, distOffset?)

Force a fog layer over everything (opacity 0..1), independent of the weather state — the game's own forced-fog lever (it uses it on the avalanche summit). Call Weather.ClearForcedFog to release it.

opacity float
expOffset opt float
distOffset opt float
Weather.ClearForcedFog()

Release the forced fog layer set by Weather.ForceFog.

World

World.Current

The active world the StreamingManager is currently streaming, or null pre-gameplay.

World.CurrentMapKey

The identity key of the current map — a shipped mountain's world name (e.g. "Kami"), or a custom level's "cml:" address. Null when not in a level. Map-bound data (bookmarks, routes) binds to this.

World.MapKeyOf(level)

The identity key a level will have once loaded — the same rule as World.CurrentMapKey, resolved from the descriptor instead of the live world. Null for a null descriptor.

level LevelDescriptor
World.DefaultSpawnPosition

Where this session's pawn first spawned — the level's default spawn (the switcher's SpawnedFrom). Null off-gameplay. Session-relative by design: it works in ANY session, not just a mod-launched one.

World.Worlds()

Every authored world, resident even when only one is streamed (from StreamingTweakables).

World.Zones(world)

Every zone of a world (its authored ZoneSceneData list).

world WorldZoneData
World.ResolveZone(world, zoneName)

Find a zone by its asset name (e.g. "01_FirstRidge") within a world.

world WorldZoneData
zoneName string
World.WorldOf(zone)

The world that owns a zone (by identity scan over the catalog), or null.

zone ZoneSceneData

WorldPrompt

WorldPrompt.Show(anchor, text, glyph?, canInteract?, style?)

Float a prompt over anchor. text is shown as-is, glyph is the button icon (see CairnAPI.Glyph, null = none). style tunes the float distance / wall-stick and whether it follows a moving anchor (null = the close default, ~1/3 of the game's wall-mount distance — live-tuned). Returns a handle for WorldPrompt.Hide. This drives our OWN widget, so a new Show replaces the previous mod prompt on it (one mod world prompt at a time); the game's own world prompts are untouched.

anchor Transform
text string
glyph opt InputAction
canInteract opt bool
style opt WorldPromptStyle
WorldPrompt.Hide(handle)

Remove a world prompt. Safe on an invalid / already-hidden handle.

handle WorldPromptHandle
WorldPrompt.Ui

OUR OWN world-prompt widget — a lazily-BUILT WorldGameplayPromptUI (from scratch, no clone), so a mod prompt coexists with the game's own in-world prompts instead of clobbering the single shared widget. Null before in-game UI init (the build needs the game's fonts/materials/sprites loaded).

WorldPromptBuilder

WorldPromptBuilder.WorldTextStyle(tmp)

Configure a world-prompt TMP so PLAIN text (written by us or the glyph component) routes to a TMP_SubMeshUI and renders through the after-image pass: fontStyle=Bold → Boxed-DemiBold SDF (index ≥1). A component-level property, so it survives the glyph's per-frame raw text writes — no tag-wrapping.

tmp TextMeshProUGUI
WorldPromptBuilder.Build()

Construct a fresh, independent WorldGameplayPromptUI under GlobalUIs (DontDestroyOnLoad). Returns the live component (Awake/OnEnable have run; the widget self-hides until Display), or null pre-asset-load (the build needs the game's fonts/materials/sprites loaded) or on any construction failure.

WorldPromptHandle

Opaque handle to a shown CairnAPI.WorldPrompt. Pass it back to WorldPrompt.Hide.

WorldPromptStyle

How a CairnAPI.WorldPrompt floats over its anchor (distance / wall-stick). Maps to the game's WorldGameplayPromptParameters. Defaults are ~1/3 of the game's wall-mount distance (live-tuned to sit near the target rather than far on a wall with a long leader line). Tune any field for your prompt.

WorldPromptStyle.Radius

Anchor radius. Game default 0.25; we use ~0.083.

WorldPromptStyle.WallOffset

Wall-stick push offset. Game default 0.2; we use ~0.067 (small = stays near the anchor).

WorldPromptStyle.MaxHeight

Max height it floats to. Game default 1.3; we use ~0.43.

WorldPromptStyle.HeightOffset

Height above the anchor. Game default 0.2; we use ~0.067.

WorldPromptStyle.UpsideDown

Flip vertically.

WorldPromptStyle.FollowsAnchor

Whether the prompt follows a moving anchor. true → a per-frame position pump; false → zero pump.

WorldPromptStyle.Default

The close default (~1/3 of the game's wall-mount distance).