CiCisTrinketAndBindingFramework
Library for White Knuckle. Lets mods register custom Trinkets, Bindings, and gamemode modes. v2.1.2: Mass Damper now disables leaderboards in endless modes (where it isn't normally available).
By CiCisMods
| Date uploaded | a month ago |
| Version | 2.1.4 |
| Download link | CiCisMods-CiCisTrinketAndBindingFramework-2.1.4.zip |
| Downloads | 2541 |
| Dependency string | CiCisMods-CiCisTrinketAndBindingFramework-2.1.4 |
This mod requires the following mods to function
BepInEx-BepInExPack
BepInEx pack for Mono Unity games. Preconfigured and ready to use.
Preferred version: 5.4.2305README
CiCi's Trinket & Binding Framework
A library mod for White Knuckle. Lets other mods register custom Trinkets (run-start picks), Bindings (run-start picks with stronger gameplay effects), and Custom Modes (gamemode-settings toggles like vanilla Hard Mode / Iron Knuckle) so they appear in the picker and the settings panel on Fresh Game.
v2.0.0 breaking change: the 13 mutators that shipped bundled in 1.x have moved to a separate mod, NebulaetrixMutators, maintained directly by Nebulaetrix. Install it to keep Devil Daggers, Marathon, Zen, etc. The framework now exposes the CustomModeRegistry API so any mod can add its own modes the same way Nebulaetrix's does.
This mod does nothing by itself — it's a dependency for other mods.
For players
Just install it. You'll only need it if a mod you use lists this as a dependency — Thunderstore Mod Manager will install it automatically.
For modders
The framework exposes two independent registries:
TrinketRegistry— register custom Trinkets and Bindings that appear in the picker on Fresh Game.CustomModeRegistry— register custom gamemode modes (toggles like vanilla Hard Mode / Iron Knuckle) that appear in the settings panel.
The two systems are unrelated — use one, the other, or both.
Setup (shared by both systems)
Reference the framework's DLL in your .csproj, then mark your plugin so BepInEx loads us first:
using BepInEx;
using TrinketAndBindingFramework;
using UnityEngine;
using System.Collections.Generic;
[BepInPlugin("com.yourmod.example", "Example Mod", "1.0.0")]
[BepInDependency(TrinketAndBindingFramework.Plugin.GUID)]
public class ExampleMod : BaseUnityPlugin
{
private void Awake()
{
// Trinket / binding / mode registration goes here.
}
}
Trinkets & Bindings (TrinketRegistry)
The picker on Fresh Game lists every registered trinket and binding. The framework handles the UI (icon, title, description tint, mutex enforcement, pip cost), unlock bypass, item granting, and leaderboard gating. You register entries once at Awake.
Register a Trinket
A Trinket is a small starter pick — usually a starter item or perk. Examples: Wall Runner (climbing axes), Sawed-Off (shotgun + shells).
TrinketRegistry.RegisterTrinket(
id: "yourmod_my_trinket", // unique string
title: "My Trinket", // shown in picker
description: "What it does in one line.",
flavorText: "Optional italic tagline under the description.",
cost: 1, // picker slot cost
icon: myIconSprite, // 32x32-ish Sprite
itemsToGrantFactory: () => new List<Item_Object> { myItemTemplate });
All parameters except id, title, description are optional.
Register a Binding
A Binding is a run-modifier — usually changes gameplay rules and increases score. Examples: Alpine Purist (climbing tools banned, axes red & breakable), Infestation (more enemies).
TrinketRegistry.RegisterBinding(
id: "yourmod_my_binding",
title: "My Binding",
description: "Makes the run harder in some way.",
flavorText: "Optional flavor.",
cost: 1,
scoreMultiplierBonus: 0.5f, // +0.5x run score
scoreBonus: 0f, // flat bonus
icon: myIconSprite);
Same signature as RegisterTrinket — under the hood the framework just flags isBinding=true and tints the picker title differently.
Grant starter items
itemsToGrantFactory runs at run start (not at registration), so you can lazy-build your item templates without worrying about asset-manager readiness at Awake:
itemsToGrantFactory: () =>
{
try { EnsureMyItemTemplate(); } catch { }
if (MyItemTemplate == null) return new List<Item_Object>();
return new List<Item_Object> { MyItemTemplate, MyItemTemplate }; // 2 copies
}
The returned Item_Object instances are template prefabs — vanilla clones them for the player's bag.
Mutex groups (mutually-exclusive picks)
When two of your trinkets shouldn't both be selected (e.g. different starter weapon variants), wire them into a mutex group:
TrinketRegistry.RegisterTrinket(id: "yourmod_sword", title: "Sword", ...);
TrinketRegistry.RegisterTrinket(id: "yourmod_axe", title: "Axe", ...);
TrinketRegistry.RegisterTrinket(id: "yourmod_bow", title: "Bow", ...);
TrinketRegistry.RegisterMutexGroup(
groupId: "yourmod_starting_weapon",
"yourmod_sword", "yourmod_axe", "yourmod_bow");
The picker auto-deselects the others when one is chosen.
Lookup a registered runtime trinket
If you need the live Trinket ScriptableObject for an id you registered (e.g. to check selection state):
var rt = TrinketRegistry.GetRuntimeTrinket("yourmod_my_trinket");
if (rt != null) { /* ... */ }
Custom Modes (CustomModeRegistry)
The gamemode settings panel (the same one Hard Mode and Iron Knuckle live on) accepts custom toggles. Unlike trinkets they have no picker cost, no item grants, and no per-pick UI — each toggle is a checkbox that flips a static bool in your mod so your Harmony patches can branch on it. Examples: Devil Daggers, Marathon Mode, Glass Knuckle (all in NebulaetrixMutators).
The framework handles the toggle UI (difficulty color, hover credit, mutex enforcement, lock visuals), leaderboard gating, save persistence, and run-start flag sync. Mode logic stays entirely in your mod.
Register a Custom Mode
public static class MyMode
{
public static bool Enabled;
public static void Set(bool v) => Enabled = v;
}
// In Awake:
CustomModeRegistry.Register(
id: "MyMode", // unique string, save key
displayName: "My Mode", // shown on toggle
description: "What the mode does, one line.",
difficulty: CustomModeRegistry.Difficulty.Hard, // Easy/Medium/Hard/Extreme, drives toggle color
onToggle: MyMode.Set, // called when player ticks/unticks and at run-start sync
exclusiveSettingIds: null, // optional: ids that grey-out when this is on
disablesLeaderboards: true, // optional: ticking this flips the "leaderboards disabled" gate
hoverCreditText: "Mode by YourName"); // optional: shown at panel bottom on hover
CustomModeRegistry.InjectIntoGamemode("Campaign"); // required: opt into the gamemode(s) this mode appears on
Important: the mode is invisible until at least one InjectIntoGamemode(...) call lists a gamemode for it. You can call it for multiple gamemodes ("Campaign", "Chimney", etc.).
Write the gameplay patch yourself
The framework only owns the UI and the flag plumbing — your mod is responsible for the actual behavior:
[HarmonyPatch(typeof(ENT_Player), "Movement")]
internal static class MyModePatch
{
[HarmonyPostfix]
private static void Postfix(ENT_Player __instance)
{
if (!MyMode.Enabled) return;
__instance.speed = 0.1f; // do your thing
}
}
Combo names
When the active mode set exactly matches a registered combo, the green pill list in UI_GamemodeOptionsText swaps to the combo display string instead:
CustomModeRegistry.RegisterCombo(
new[] { "MyMode", "OtherMode" },
"<color=#ff9500>Total Annihilation</color>");
Gamemode aliases (for modes that redirect)
If your mode redirects one gamemode to another at load time (Marathon redirects Campaign → GM_Level_Tester), register the alias so the framework's run-start sync still reads the source's saveData:
CustomModeRegistry.RegisterGamemodeAlias("GM_Level_Tester", "Campaign");
Lock a mode as WIP
If a mode isn't shippable yet, mark it locked. The toggle shows the grey vanilla-locked visual, clicks are blocked, and any stale "on" state in saveData is stripped:
CustomModeRegistry.RegisterDisabledLock("MyWipMode", "WIP");
Mutual visual link
When two modes imply each other (one is on, the other "would also activate" if ticked), link them so the other tile tints orange while the first is on:
CustomModeRegistry.RegisterMutualLink("ModeA", "ModeB");
Runtime check
bool on = CustomModeRegistry.IsActive("MyMode");
bool anyOn = CustomModeRegistry.AnyActive();
IsActive reads from the current gamemode's HasActiveSetting, so it tracks the saved selection rather than a local cached bool. Use your own static Enabled flag inside hot paths instead.
Working examples in the wild
- CiCi's Climbing Axes —
Wall Runner(trinket),Alpine Purist(binding),Free Climber(trinket). - CiCi's Pioneer's Shotgun —
Sawed-Off(trinket),Infestation(binding). - NebulaetrixMutators — 13 custom modes registered through
CustomModeRegistry, plus combo names, a WIP-locked mode, a mutual link, and a gamemode alias. Read itsPlugin.csfor an end-to-end example covering everyCustomModeRegistryfeature.
Compatibility
- White Knuckle (current build)
- BepInEx 5.x
CHANGELOG
Changelog
2.1.3
Added
- Subtle "CiCi's Trinkets & Bindings Framework Menu — Made & Designed by: Li-0" credit line below the gamemode picker panel. Grey and unobtrusive.
2.1.2
Fixed
- Mass Damper now disables leaderboards when selected in endless modes.
2.1.1
Fixed
- Picker description scroll now uses a constant pixels/second rate (12 px/s) instead of a fixed total-time. Long descriptions no longer accelerate and stay readable at the same pace as short ones. Floor at 3s so very short overflows don't snap past.
- Top/bottom pauses bumped (1.5s / 1.0s) so there's more time to start reading before the scroll kicks in.
2.1.0
Added — Collapsible sections in the picker and gamemode-settings UI
Both pickers and the gamemode-settings panel are now organized into nested, collapsible sections. Click a section header to fold/unfold it; right-click any group header to force-expand it and everything beneath. Open/closed state persists per-section across runs (saved to BepInEx/config/cici_framework_sections.json).
Trinket & Binding pickers auto-classify each entry by source:
- White Knuckle — vanilla content, further split into Vanilla / Parasite / Chimney / Misc buckets, with Vanilla and Chimney further split into Trinkets / Items / Perks by category. Section headers are tinted to match each bucket's in-game color (pink/red for Vanilla matching the scrollbar pulse, dark green for Parasite, cryo-blue for Chimney).
- CiCi's Trinkets / Bindings — gold header. Sub-leaves per CiCi mod (Trinket & Binding Framework, Climbing Axes, Shotgun, Lidar Vision, Fake Wand, …) detected automatically from any
com.cicismods.*plugin GUID. - Modded — non-CiCi external mods, one sub-leaf per mod, labeled with the mod's
BepInPlugindisplay name.
Gamemode settings panel uses the same shape: Vanilla / CiCi's Modes / Modded.
Each header pulses with a soft brightness oscillation, hover-scales slightly, and plays the vanilla UI hover/click sounds. Auto-detection happens at registration time by stack-walking inside RegisterTrinket / RegisterBinding / CustomModeRegistry.Register — consumer mods don't need to do anything.
Other
- Picker description panel pauses (1.5s → 0.75s) shortened so descriptions scroll into motion sooner.
- Bindings picker now reflows to a max of 4 columns and gracefully drops to fewer when the panel is narrow.
2.0.0
Breaking: mutators are no longer bundled. They now live in a separate mod, NebulaetrixMutators, maintained directly by Nebulaetrix. Install that mod to keep all 13 modes (Devil Daggers, Marathon, Zen, etc.) available on Campaign's settings panel.
Added — Public CustomModeRegistry API
Other mods can now register their own custom gamemode modes through a public API, the same way they already register trinkets and bindings.
using TrinketAndBindingFramework;
// In your Plugin's Awake:
CustomModeRegistry.Register(
id: "MyMode",
displayName: "My Custom Mode",
description: "What this mode does",
difficulty: CustomModeRegistry.Difficulty.Hard,
onToggle: enabled => { MyMode.Enabled = enabled; },
exclusiveSettingIds: null,
disablesLeaderboards: true,
hoverCreditText: "Mode by YourName"
);
CustomModeRegistry.RegisterCombo(new[] { "MyMode", "OtherMode" }, "<color=#ff9500>Combo Name</color>");
CustomModeRegistry.RegisterDisabledLock("WIPMode", "WIP");
CustomModeRegistry.RegisterMutualLink("ModeA", "ModeB");
CustomModeRegistry.RegisterGamemodeAlias("GM_Level_Tester", "Campaign");
CustomModeRegistry.InjectIntoGamemode("Campaign");
The framework handles the picker UI (toggle visual, mutex enforcement, difficulty-colored title, hover-credit text), leaderboard gating, combo display in the green pill list, and save-data persistence. Mode logic stays entirely in your mod.
Removed
- All 13 mutator mode classes and their Harmony patches moved to NebulaetrixMutators.
more_mutators_assetsAssetBundle moved to NebulaetrixMutators.- Removed
MutatorRegistry,MutatorPickerIntegration,MutatorCredit,MarathonBackwardLink, and related types — replaced by the genericCustomModeRegistry/CustomModePickerIntegration/CustomModeCredit/CustomModeLinksinfrastructure.
1.4.0
13 Mutator Modes from Nebulaetrix's MoreMutators (v1.1.2) are now live on Campaign's settings panel. Marathon assembles a custom ~110-level Campaign chain end-to-end, mutator combos get fun custom names, and the trinket picker auto-scrolls long descriptions.
Huge thanks to Nebulaetrix for letting me bring MoreMutators content into this framework.
Added — Mutator Modes (on Campaign's settings panel)
- Devil Daggers (Easy) — shoot rebar from your hands. Hold the fire button (~0.1s) to launch. Combine with Volatile for explosive rebar.
- Zen Mode (Easy) — no mass, bloodbugs, teeth, turrets, vent things. HP capped low.
- Zero-G (Easy) — gravity off, drag reduced.
- Volatile (Medium) — random explosions trigger around you.
- Markiplier% (Medium) — bag inventory disabled.
- Amputated (Hard) — right hand locked, upgrade consoles destroyed.
- Baby Knuckle (Hard) — 50% scale, tweaked hold/jump/speed, weapon recoil.
- Disoriented (Hard) — camera flipped 180°.
- Glass Knuckle (Hard) — 0.1 max HP, one-shot to anything.
- Paraplegic (Hard) — jump disabled.
- Marathon Mode (Extreme) — full ~110-level Campaign chain end-to-end, silos → pipeworks → habitation → abyss (no Chimney / LadderWarp / Foundations clutter). Within-family chunks reshuffle per run.
- Wind Tunnel (Extreme) — constant downward blizzard.
- Backward (elkcunK etihW) — staged as WIP, locked in the picker for now.
Added — Picker UX
- Auto-scrolling description box. Long trinket / binding descriptions now bob top → bottom → top with pauses inside a masked viewport. Short descriptions (e.g. Carabiner) skip the wrapper entirely so the text shows exactly like vanilla.
- Per-mutator credit hover. Hovering any of the 13 ported mutators shows "Custom mode originally made by Nebulaetrix (MoreMutators Mod)" under the settings panel.
Removed
- Helping Hand mutator (player can already give themselves perks through the picker).
1.3.1
Fixed
- Linux install: archive was packed with backslash path separators, which Linux extractors treated as part of the filename instead of as folders. Repackaged with spec-compliant forward slashes so the mod installs cleanly without manual file moves.
1.3.0
Polished picker UX: leaderboard handling is now per-selection, slot indicator handles stacked items, scrolling feels smooth, and each grid has its own pulsing scrollbar.
Added
- Centralized leaderboard gating. The picker now disables leaderboards only when the player has actually picked something that warrants it, and re-enables them when those selections are cleared. A red LEADERBOARDS DISABLED label appears at the top of the picker while disabling selections are active.
- In Campaign, Chimney, and Endless modes (which natively shipped the picker): only framework-pooled entries, external mod entries, and Contortions Totem disable leaderboards. Picking only the vanilla picker entries (Carabiner, Iron Knuckle, Pitons & Beans, etc.) keeps leaderboards on.
- In every other gamemode (Challenge, Parasite, tutorials, dev): the picker still works, but any selection disables leaderboards.
- Stack-aware slot indicator. The pip bar at the top-right of the picker now counts each stack of a stackable trinket as one slot instead of one slot per trinket type. Stack a perk three times → three pips light up.
- Slot indicator overflow. Past 5 slots the bar shows a
[+N]overflow indicator instead of growing off-screen. - Smooth wheel scrolling. The picker's icon grids glide on a smooth-damp curve instead of snapping a fixed distance per wheel notch.
- Per-grid scrollbars with pulsing handles — magenta for trinkets, red for bindings — visible whenever the grid actually has overflow.
1.2.1
Added
- Holiday Piton, Holiday Rebar, and Holiday Rope Rebar start-of-run trinkets — Christmas/Chimney variants of the existing climbing-item starters. Cryo-blue titles, route into the Chimney bucket in the picker.
1.2.0
Vanilla picker is now content-rich out of the box: every vanilla perk shows up as a Trinket or Binding, and most vanilla items show up as start-of-run grants.
Added
- Every vanilla Perk is now mirrored into the picker as either a Trinket (beneficial) or Binding (gameplay change), with category-tinted title colors.
- Vanilla tools as one-pick Trinkets (Cryo-Gun, Flare Gun, Flashlight, Wrench, Scanner) — mutex-locked so only one tool starts the run.
- Vanilla artifacts as one-pick Trinkets (Glove, Remote, Spear, Timepiece, Translocator) — mutex-locked.
- Vanilla consumables as stackable Trinkets, max 12 each (Blink Eye, Canned Food, Delta-0052, Food Bar, Grub, Injector, Inoculator, Lemon Roach, Milk, Pills, Hot Cocoa, Cookie, Candy Cauldron).
- Vanilla climbing items as stackable Trinkets, max 12 each (Rope Rebar, Explosive Rebar, Rope, Auto Piton, Brick, Piton, Rebar).
- Vanilla misc / Other items as stackable Trinkets, max 12 each (Flare, Gold/Platinum/Ruby Roach, Floppy Disks T1–T3).
- New No Hammer binding: bans the starting hammer + any world-spawned hammer for the run.
- Stack-count overlay on stackable trinkets — left-click adds a stack, right-click removes one.
- Picker scroll on the trinket and binding grids so the bigger entry list still fits.
- Picker ordering is now bucketed: vanilla originals first, external mods next, framework-added entries last (sub-sorted by Vanilla → Halloween/Parasite → Christmas/Chimney update, then category, then grey-then-colored, then tier).
API
- Public
TrinketRegistry.BucketandCategoryenums for mods that want to slot themselves into the framework's ordering.
1.1.0
Picker now appears in every gamemode — Challenge, Parasite, and any future modes — and every vanilla trinket / binding shows up too.
1.0.0
Initial release.
Added
- Public
TrinketRegistryAPI for mods to register custom Trinkets (run-start modifiers) and Bindings (run-start modifiers with stronger gameplay effects). - Trinkets and Bindings registered via this framework appear in the run-start picker on Fresh Game.
- Per-trinket
itemsToGrantFactorycallback runs at gamemode start to hand the player starter items. - Custom icons, custom display names, custom descriptions, and custom title-color tags are all supported.
Notes
- This mod is a library. It does nothing on its own.