Crafting Techniques

Crafting techniques are active abilities used during the crafting process to manipulate materials, manage resources, and influence outcomes.

Interface

interface CraftingTechnique {
  name: string;
  displayName?: Translatable;
  icon: string;
  realm: Realm;

  type: CraftingTechniqueType; // 'fusion' | 'refine' | 'support' | 'stabilize'

  // Resource costs
  stabilityCost: number;       // Stability removed from current when used
  poolCost: number;             // Qi drawn from pool when used
  noQiCost?: boolean;           // Pool cost is zero, whatever poolCost says
  toxicityCost?: number;        // Toxicity added to the crafter when used
  dropletCost?: number;         // Qi droplets consumed when used

  // Effects
  effects: CraftingTechniqueEffect[]; // What happens when technique is used

  // Triggered effects (walked for tooltip substitution, see Tooltip Templates below)
  triggeredEffects?: { trigger: string; effects: CraftingTechniqueEffect[] }[];

  // Requirements
  conditionRequirement?: CraftingCondition; // Condition that must hold to use it
  buffRequirement?: { buff: CraftingBuff; amount: number };
  buffCost?: { buff: CraftingBuff; amount: number };
  firstActionOnly?: boolean;    // Only usable on the first action of a craft
  minStability?: number;        // Only usable while current stability is above this

  // Mastery upgrades
  upgradeMasteries?: { [key: string]: CraftingTechniqueMasteryRarityMap };
  masteryKindPools?: CraftingTechniqueEffectKind[];
  tooltip?: string;
  successChance: number;        // 0-1 probability (1 always succeeds)
  cooldown: number;
  currentCooldown: number;
}

Technique Types

Four technique types drive all crafting:

Fusion (fusion)

Increases completion progress. The foundational technique type for basic crafting.

type: 'fusion',
effects: [
  {
    kind: 'completion',
    amount: { value: 1, stat: 'control', upgradeKey: 'completion' },
  }
]

Refine (refine)

Increases perfection progress. Higher risk/reward — often has stricter requirements or higher stability costs.

type: 'refine',
effects: [
  {
    kind: 'perfection',
    amount: { value: 1.5, stat: 'control', upgradeKey: 'perfection' },
  }
]

Support (support)

Applies helpful buffs to the crafter or the craft itself. Does not directly advance progress.

type: 'support',
effects: [
  {
    kind: 'createBuff',
    buff: swiftHands,
    stacks: { value: 1, stat: undefined, upgradeKey: 'stacks' },
  }
]

Stabilize (stabilize)

Restores current stability and applies stability-related buffs. Critical for managing risk in complex crafts.

type: 'stabilize',
effects: [
  {
    kind: 'stability',
    amount: { value: 0.5, stat: 'control', upgradeKey: 'stability' },
  }
]

Resource Costs

Understanding stability costs is critical for balanced technique design:

// Reduces current stability when the technique is used
stabilityCost: 5,

// Qi pool consumption
poolCost: 20,

// Optional: this technique does not lower the max stability ceiling
noMaxStabilityLoss: true,

Stability mechanics:

  • Current stability falling to 0 causes craft failure
  • stabilityCost is taken out of current stability when the technique resolves
  • Every action adds a stability penalty, and that penalty is subtracted from the recipe’s stability to give the ceiling for current stability
  • noMaxStabilityLoss on the technique stops it adding to that penalty, so the ceiling is not lowered by using it
  • A maxStability effect changes the penalty directly, and a buff with sealedMaxStability stops the ceiling from rising at all

Effects Reference

Completion (completion)

Advances the completion meter:

{
  kind: 'completion',
  amount: { value: 1, stat: undefined },
}

Perfection (perfection)

Advances the perfection meter:

interface PerfectionEffect {
  kind: "perfection";
  amount: Scaling;
  condition?: CraftingTechniqueCondition;
}

Stability (stability)

Restores current stability:

const restoreStability: CraftingTechniqueEffect = {
  kind: 'stability',
  amount: { value: 1, stat: 'control' },
};

Buff Effects

Apply or consume crafting buffs:

const buffEffects: CraftingTechniqueEffect[] = [
  { kind: 'createBuff', buff: craftingBuff, stacks: { value: 1, stat: undefined } },
  { kind: 'consumeBuff', buff: craftingBuff, stacks: { value: 1, stat: undefined } },
  { kind: 'modifyBuffGroup', group: 'buffGroupName', amount: { value: 1, stat: undefined }, mode: 'all' },
];

mode — Controls which matching buffs are affected:

  • 'all' (default): affects every matching buff
  • 'highest': affects the matching buff with the most stacks
  • 'lowest': affects the matching buff with the fewest stacks
  • 'random': affects one randomly chosen matching buff

Conditional Effects

Effects can be conditional based on current crafting state:

{
  kind: 'perfection',
  amount: { value: 1, stat: 'control', upgradeKey: 'perfection' },
  condition: {
    kind: 'condition',
    condition: 'currentStability > 50',
  },
}

Scaling Reference

All amount fields use the Scaling type for stat-based values:

{
  value: number;              // Base value
  stat?:                      // Stat to scale from (e.g. 'control', 'intensity')
    | PhysicalStatistic
    | SocialStatistic
    | CombatStatistic
    | CraftingStatistic
    | TechniqueElement
    | undefined;
  upgradeKey?: string;        // Links to mastery upgrade
  eqn?: string;               // Custom expression multiplied onto the result (e.g. 'floor(perfectionPercentage / 100)')
  additiveEqn?: string;       // Expression added after eqn multiplication
  max?: Scaling;              // Maximum value cap
}

The stat field takes any physical, social, combat or crafting statistic, or a technique element. The stats the game’s own crafting techniques scale off are power, control, intensity, maxhp, maxbarrier, maxtoxicity, maxpool and artefactpower. Use undefined for a flat value that ignores the crafter’s stats.

Registration

Use addCraftingTechnique to register a technique with the game:

window.modAPI.actions.addCraftingTechnique({
  name: 'Custom Fusion',
  icon: 'assets/custom-fusion.png',
  realm: 'bodyForging',
  successChance: 1,
  cooldown: 0,
  currentCooldown: 0,
  type: 'fusion',
  stabilityCost: 10,
  poolCost: 15,
  effects: [
    {
      kind: 'completion',
      amount: { value: 2, stat: 'control' },
    },
  ],
});

Mastery System

Crafting techniques can be upgraded through the mastery system. All helper functions are available on window.modAPI.utils.

Quick Reference

upgradeMasteries: {
  completion: window.modAPI.utils.createCraftingCompletionUpgradeMap('completion', 'empowered'),
  perfection: window.modAPI.utils.createCraftingPerfectionUpgradeMap('perfection', 'empowered'),
  pool: window.modAPI.utils.createCraftingPoolUpgradeMap('pool', 'empowered'),
  stability: window.modAPI.utils.createCraftingStabilityUpgradeMap('stability', 'empowered'),
  stacks: window.modAPI.utils.createCraftingStacksUpgradeMap('stacks', 'resplendent', 'Empower Intensity', 2),
  cost: window.modAPI.utils.createCraftingCostUpgradeMap('poolCost', 'empowered', 'Qi Pool', -5),
}

Rarity Tiers

Crafting technique masteries use the same rarity tiers as combat techniques:

RarityTier numeral
mundaneI
qitouchedII
empoweredIII
resplendentIV
incandescentV
transcendentVI

The helpers take the rarity name, for example createCraftingCompletionUpgradeMap('completion', 'empowered'). The tier numerals are for display and for ordering, not for arguments.

Upgrade Types

The upgradeMasteries field maps upgrade keys to a CraftingTechniqueMasteryRarityMap, defining how the technique improves at each mastery tier. Use the helper functions from the mastery system:

Effect Upgrades

Increase completion/perfection/pool/stability amounts multiplicatively (5% mundane to 30% transcendent):

upgradeMasteries: {
  completion: window.modAPI.utils.createCraftingCompletionUpgradeMap('completion', 'empowered'),
  perfection: window.modAPI.utils.createCraftingPerfectionUpgradeMap('perfection', 'empowered'),
  pool: window.modAPI.utils.createCraftingPoolUpgradeMap('pool', 'empowered'),
  stability: window.modAPI.utils.createCraftingStabilityUpgradeMap('stability', 'empowered'),
}

Each function takes (upgradeKey: string, startRarity: Rarity). The upgradeKey must match the upgradeKey on the Scaling object of the effect you want upgraded.

There is also createCraftingPowerUpgradeMap(key, rarity, tooltip) for custom effect scaling — it applies the same multiplicative upgrade percentages but accepts a custom tooltip string.

Generic Builders

For full control over per-rarity values:

  • createCraftingUpgradeMap(key, rarity, upgrades) — Explicit per-rarity tooltip/change/shouldMultiply. Omit a rarity by passing undefined.
  • createCraftingUpgradeMapSimple(key, rarity, tooltip, shouldMultiply, changes, renderTransform?) — One tooltip template with {change} placeholder; per-rarity numbers in changes.
  • createCraftingUpgradeMapStepped(key, rarity, tooltip, maxChange) — Automatically steps the value from maxChange/5 (mundane) up to maxChange (incandescent).

Buff Stack Upgrades

Increase the number of buff stacks granted:

upgradeMasteries: {
  stacks: window.modAPI.utils.createCraftingStacksUpgradeMap('stacks', 'resplendent', 'Empower Intensity', 2),
}

createCraftingStacksUpgradeMap(key, startRarity, buffName, maxChange) — maxChange is the maximum stack change at Transcendent tier.

Cost Reductions

Lower resource consumption (pool cost, stability cost):

upgradeMasteries: {
  poolCost: window.modAPI.utils.createCraftingCostUpgradeMap('poolCost', 'empowered', 'Qi Pool', -5),
}

createCraftingCostUpgradeMap(key, startRarity, costName, maxChange) — costName appears in the mastery tooltip. Use negative maxChange to reduce costs.

Max Amount Increases

Increase the maximum amount of a stepped value:

upgradeMasteries: {
  maxStacks: window.modAPI.utils.createCraftingMaxIncreaseUpgradeMap('maxStacks', 'resplendent', 'Max Stacks', 3),
}

createCraftingMaxIncreaseUpgradeMap(key, startRarity, buffName, maxChange) — useful for techniques that cap at a certain amount.

Success Improvements

Success chance is automatically added by the game as a mastery bonus for any technique with successChance < 1. You do not need to define it in upgradeMasteries.

masteryKindPools

By default, the game determines which mastery upgrades are available based on a technique’s effect kinds (completion, perfection, pool, stability, etc.). Setting masteryKindPools overrides this list:

masteryKindPools: ['completion', 'pool'], // Only offer completion and pool mastery upgrades

This is useful when a technique has multiple effect kinds but you only want mastery selection to draw from a subset.

Custom Thresholds

A recipe can define a named custom threshold — a quality milestone that runs its own event outcome in place of the sublime one when cleared. This lets a craft award different results depending on how well the player performed beyond mere perfection.

Define the threshold in the recipe:

export const myRecipe: Recipe = {
  id: 'my_recipe',
  name: 'Celestial Pill',
  // ... other fields ...
  customThreshold: {
    name: 'Celestial Radiance',
    threshold: 3, // Clear at 3 perfection tiers above perfect
    tooltip: 'Achieve true perfection with the celestial radiance.',
  },
  sublimeSteps: [{ kind: 'text', text: 'You produce a sublime pill.' }],
  perfectSteps: [{ kind: 'text', text: 'You produce a perfect pill.' }],
  outcomeSteps: [
    // Called when custom threshold is NOT met (falls back to sublime outcome)
    { kind: 'text', text: 'The pill absorbs the celestial energy.' },
    // Called when custom threshold IS met
    { kind: 'text', text: 'The pill blazes with celestial radiance!' },
  ],
};

The CraftCustomThreshold interface:

interface CraftCustomThreshold {
  /** Title shown on the quality bar. */
  name: Translatable;
  /** Quality tiers the craft has to reach to clear the mark. */
  threshold: number;
  /** Tooltip for the bar. A generic line is used when this is unset. Both this and
   *  the generic line are given `{needed}` (the threshold) and `{name}`. */
  tooltip?: Translatable;
}

When the threshold is met, the craft’s outcomeSteps fires with the threshold’s name available via {name} in text. When it is not met, the sublime outcome fires instead.

Tooltip Templates

The tooltip field on a crafting technique supports dynamic placeholders that resolve at render time. The system walks both the main effects block and each triggeredEffects block, populating template values for each effect. This means you can reference values from triggered effects in your tooltips:

// In a crafting technique:
tooltip: 'When you gain {createBuff.buff} gain {createBuff.stacks} extra stacks.',
effects: [
  {
    kind: 'createBuff',
    buff: someCraftingBuff,
    stacks: { value: 1, stat: undefined },
  },
],
triggeredEffects: [
  {
    trigger: 'onFusion',
    effects: [
      {
        kind: 'createBuff',
        buff: someCraftingBuff,
        stacks: { value: 1, stat: undefined },  // can use {createBuff.stacks} in tooltip
      },
    ],
  },
],

Template Value Keys

For each effect, the following keys are registered in the template scope:

FormExampleNotes
Bare{createBuff.amount}Refers to the effect in the main effects block
Kind-qualified{buffSelf.stacks}kind is the effect’s kind value
Indexed{[0].amount}Position in the effects array
Trigger-prefixed{trigger0.[0].amount}Effect at index 0 of triggeredEffects[0]
Nested trigger{trigger0.createBuff.amount}Same as above, kind-qualified form

Both stacks and amount are available on createBuff / consumeBuff effects for use in authored tooltips.