---
name: set-crafting-an-item
description: How to craft items and run an orb economy with the Set World API. Use when buying an exact material grade, spending orbs on the price-gated lottery and reading its exact odds, salvaging items, pricing monster drops or stat boosts, reading the schemas of the craft, salvage, drop and boost responses, or composing these into a progression loop and wallet your game controls.
license: Free to use when obtained from set.world, commercially too (the API, what it returns, the skills and downloaded models). The source code of Set is © Jimmy Lee under CC BY-NC 4.0 and its commercial use needs a paid waiver.
metadata:
  version: "0.8.9"
  title: Crafting an item
---

# Crafting an item

This skill owns Set's orb economy: every price, both ways to craft, salvage, drops and stat boosts. Everything is priced in one currency, orbs, and every price is deterministic.

| Set provides | Your game owns |
| --- | --- |
| Crafting, end to end: one graded item per request | When players craft, and what they pay with |
| Prices for crafts, salvage, drops and stat boosts | Wallets, balances and inventories |
| Grades, rarity and orb values | What drops what, and how often |

A crafted item is an ordinary `Item` ([Rolling an item](https://set.world/skills/rolling-an-item)). Its price does not set its damage, weight or reach.

## Orbs are your game's currency

Set prices everything in orbs and holds none. There is no wallet, no balance and no rule for how an orb is earned. An orb exists only as a number your game tracks, and the `orbs=` or `tier=` you send is a spend your game has already checked against its own ledger. This is deliberate: every game keeps its own economy and uses orbs as the bridge to Set.

- **Earn them your way.** Set can price a kill (`/api/drop`), but quests, shops, time, trade or real play are all yours to price.
- **Convert your own resources.** A game with wood, stone, ore, gold or anything else sets a rate from each resource to orbs, converts what the player pays, and sends the total to `/api/craft`. The player may never see the word "orb".
- **Your rates, Set's odds.** The rate, the sinks and whether orbs convert back are your design. Set's side never moves: one orb buys the same odds in every game.

An example with invented rates:

| Your resource | Orbs per unit |
| --- | ---: |
| wood | 1 |
| stone | 2 |
| iron ore | 10 |

A player pays 20 wood, 15 stone and 8 iron ore: `20 × 1 + 15 × 2 + 8 × 10 = 130` orbs. Your game can now call `/api/craft?orbs=130` (a lottery of 2 candidates whose median result is Grade C), or buy a Grade C (125 orbs) guarantee and keep the change.

```ts
type ExchangeRates = Record<string, number>;                     // orbs per unit of your resource
type Payment = Array<{ resource: string; units: number }>;

const RATES: ExchangeRates = { wood: 1, stone: 2, 'iron ore': 10 };
const toOrbs = (payment: Payment) => payment.reduce((orbs, part) => orbs + part.units * RATES[part.resource], 0);
```

What orbs buy for one item, one character and a whole roster is shown in [Rolling an item](https://set.world/skills/rolling-an-item), [Rolling a character](https://set.world/skills/rolling-a-character) and [Rolling a group](https://set.world/skills/rolling-a-group). The prices and odds follow.

## The prices

| System | Formula |
| --- | --- |
| Guarantee craft | `craftCost(tier) = 5^(tier − 1)` |
| Salvage | `floor(craftCost × 10%)` |
| Stat boost | A price per step, cubic at first and steep at the top (the table under Stat boosts). 8 → 24 costs 53,337 |
| Monster drop | `floor(round((avgStat − 6)² / 4) × classMultiplier × uniform(0.75, 1.25))` |

The values per grade are in the tables below.

An item's `orbValue` is its grade's guarantee price. Which materials are in which grade is in [Materials](https://set.world/skills/item-materials).

## Mode 1: guarantee a grade

Pay a fixed price for exactly one grade. The server samples until it draws that grade or its attempt budget runs out. Quality, prefix and suffix are ordinary single draws.

```sh
curl 'https://set.world/api/craft/cost?tier=5'
curl 'https://set.world/api/craft?tier=5&seed=11'
```

```ts
type CraftCost = { tier: number; orbs: number; defaultBudget: number };

// Item and SlotBreakdown are defined in Rolling an item; Grade and Material in Materials.
type CraftedItem = Item & { breakdown: SlotBreakdown };

type GuaranteeCraft = {
  mode: 'tier';
  requestedTier: number;           // 1..7 = Grade F..S
  seed: number | null;
  contentVersion: string;
  budget: number;                  // the effective attempt budget
  item: CraftedItem;
  score: number;
  materialRank: number;
  tier: number;                    // equals requestedTier unless capped
  tierGrade: Grade;
  tierName: string;
  material: Material;
  attempts: number;
  capped: boolean;                 // true when the budget ran out
};
```

The two requests above, answered at this `contentVersion`:

```json
{ "tier": 5, "orbs": 625, "defaultBudget": 62500 }
```

```json
{
  "mode": "tier",
  "requestedTier": 5,
  "seed": 11,
  "contentVersion": "4.swpi78HUCtcrZ1Eoi9dipw",
  "budget": 62500,
  "item": {
    "name": "gold coil",
    "slot": "waist",
    "slotIndex": 16,
    "props": [
      { "name": "-", "weight": 60000 },
      { "name": "-", "weight": 489 },
      { "name": "gold", "weight": "16299" },
      { "name": "coil", "weight": "49800" },
      { "name": "-", "weight": "1099" }
    ],
    "roll": [119487, 375, 703966, 80505, 39341, 584289, 147573, 9121, 11, 121, 210389, 149257, 121774, 69979, 143393, 19815, 134487, 15735, 574],
    "indexes": [4, 0, 19, 1, 11, 12, 3, 0, 11, 121, 5, 3, 2, 1, 3, 0, 2, 0, 0],
    "score": 4.1045,
    "materialRank": 21,
    "tier": 5,
    "tierGrade": "B",
    "tierName": "Grade B",
    "orbValue": 625,
    "material": { "name": "gold", "materialRank": 21, "tier": 5, "tierGrade": "B", "tierName": "Grade B" },
    "affects": ["stamina", "carryCapacity"],
    "breakdown": {
      "slot": "waist",
      "affects": ["stamina", "carryCapacity"],
      "items": [
        {
          "name": "gold coil",
          "orbValue": 625,
          "materialRank": 21,
          "tier": 5,
          "tierGrade": "B",
          "score": 4.1045,
          "tierName": "Grade B",
          "material": { "name": "gold", "materialRank": 21, "tier": 5, "tierGrade": "B", "tierName": "Grade B" }
        }
      ]
    }
  },
  "score": 4.1045,
  "materialRank": 21,
  "tier": 5,
  "tierGrade": "B",
  "tierName": "Grade B",
  "material": { "name": "gold", "materialRank": 21, "tier": 5, "tierGrade": "B", "tierName": "Grade B" },
  "attempts": 3,
  "capped": false
}
```

The server drew 3 candidates before one had the requested grade.

| Grade | Tier | Orbs | Default budget |
| --- | --- | ---: | ---: |
| F | 1 | 1 | 100 |
| E | 2 | 5 | 500 |
| D | 3 | 25 | 2,500 |
| C | 4 | 125 | 12,500 |
| B | 5 | 625 | 62,500 |
| A | 6 | 3,125 | 312,500 |
| S | 7 | 15,625 | 1,000,000 |

- `budget` is optional in tier mode only, a positive integer capped at 1,000,000. `budget` with `orbs` returns 400.
- `capped: true` means the budget ran out; the response then holds the highest grade below the target that it drew, or the lowest grade above it if every draw was above. At the default budget this practically never happens; a small explicit `budget` can miss.
- A guarantee buys a grade, not a material: a Grade S guarantee is godhair about 1.6% of the time.

## Mode 2: the price-gated lottery

```sh
curl 'https://set.world/api/craft?orbs=125&seed=11'
```

Spend N orbs (capped at 15,625) to draw `max(1, round((N / 25)^0.55))` candidates (`lottery-3`). Each candidate's grade T is accepted with probability `min(1, (N / craftCost(T))^1.7)` and redrawn otherwise, so a grade opens fully only once N reaches its guarantee price. The item keeps the slot, gear and material of the best-grade candidate (the rarer material breaks ties) and takes the rarest quality, prefix and suffix among all candidates. There is no grade guarantee.

```ts
type LotteryCraft = {
  mode: 'orbs';
  orbs: number;                    // the effective spend, after the cap
  rolls: number;                   // candidates drawn
  lottery: { version: string; candidateBase: number; candidateExponent: number; gateExponent: number; traitFactors: string[]; traitSelection: string };   // the rule in force
  seed: number | null;
  contentVersion: string;
  item: CraftedItem;
  score: number;
  materialRank: number;
  tier: number;
  tierGrade: Grade;
  tierName: string;
  material: Material;
  rollsExpected: { medianTier: number; medianScore: number; p25Score: number; p75Score: number; p95Score: number; referenceOrbs: number; method: 'historical-sample' };
  gradeExpectations: {
    method: 'exact-weighted-model';
    orbs: number;
    rolls: number;
    medianTier: number;
    medianGrade: Grade;
    distribution: Array<{ tier: number; tierGrade: Grade; probability: number; atLeastProbability: number; cumulativeProbability: number }>;   // seven rows, F to S
  };
  analysis: {
    itemProbability: number;               // the six factors' joint probability on one roll: 10^(−score)
    gradeOrBetterProbability: number;      // this grade or better on one ordinary roll
    gradeOrBetterCraftProbability: number; // this grade or better from this craft
    maxRarityScore: number;
    rarityFraction: number;                // score / maxRarityScore: progress toward a log ceiling, not a percentile
    maxMaterialRank: number;
    maxOrbValue: number;
    factors: Array<{ slot: string; name: string; p: number; contribution: number }>;   // largest contribution first
  };
};
```

The request above, answered at this `contentVersion`:

```json
{
  "mode": "orbs",
  "orbs": 125,
  "rolls": 2,
  "lottery": {
    "version": "lottery-3",
    "candidateBase": 25,
    "candidateExponent": 0.55,
    "gateExponent": 1.7,
    "traitFactors": ["quality", "prefix", "suffix"],
    "traitSelection": "rarest-among-candidates"
  },
  "seed": 11,
  "contentVersion": "4.swpi78HUCtcrZ1Eoi9dipw",
  "item": {
    "name": "copper belt",
    "slot": "waist",
    "slotIndex": 16,
    "props": [
      { "name": "-", "weight": 60000 },
      { "name": "-", "weight": 489 },
      { "name": "copper", "weight": "47400" },
      { "name": "belt", "weight": "60000" },
      { "name": "-", "weight": "1099" }
    ],
    "roll": [110450, 345, 506318, 331738, 39390, 383232, 30697, 190398, 88, 64, 203105, 239306, 189114, 93426, 133102, 35845, 37273, 96332, 511],
    "indexes": [4, 0, 14, 6, 11, 7, 0, 3, 88, 64, 5, 4, 3, 1, 2, 0, 0, 3, 0],
    "score": 3.56,
    "materialRank": 6,
    "tier": 2,
    "tierGrade": "E",
    "tierName": "Grade E",
    "orbValue": 5,
    "material": { "name": "copper", "materialRank": 6, "tier": 2, "tierGrade": "E", "tierName": "Grade E" },
    "affects": ["stamina", "carryCapacity"],
    "breakdown": {
      "slot": "waist",
      "affects": ["stamina", "carryCapacity"],
      "items": [
        {
          "name": "copper belt",
          "orbValue": 5,
          "materialRank": 6,
          "tier": 2,
          "tierGrade": "E",
          "score": 3.56,
          "tierName": "Grade E",
          "material": { "name": "copper", "materialRank": 6, "tier": 2, "tierGrade": "E", "tierName": "Grade E" }
        }
      ]
    }
  },
  "score": 3.56,
  "materialRank": 6,
  "tier": 2,
  "tierGrade": "E",
  "tierName": "Grade E",
  "material": { "name": "copper", "materialRank": 6, "tier": 2, "tierGrade": "E", "tierName": "Grade E" },
  "rollsExpected": { "medianTier": 4, "medianScore": 7.16, "p25Score": 5.06, "p75Score": 8.13, "p95Score": 10.75, "referenceOrbs": 125, "method": "historical-sample" },
  "gradeExpectations": {
    "method": "exact-weighted-model",
    "orbs": 125,
    "rolls": 2,
    "medianTier": 4,
    "medianGrade": "C",
    "distribution": [
      { "tier": 1, "tierGrade": "F", "probability": 0.04701463893779001, "atLeastProbability": 1, "cumulativeProbability": 0.04701463893779001 },
      { "tier": 2, "tierGrade": "E", "probability": 0.12384533203963122, "atLeastProbability": 0.95298536106221, "cumulativeProbability": 0.17085997097742123 },
      { "tier": 3, "tierGrade": "D", "probability": 0.25677908734042176, "atLeastProbability": 0.8291400290225788, "cumulativeProbability": 0.427639058317843 },
      { "tier": 4, "tierGrade": "C", "probability": 0.5628310133306484, "atLeastProbability": 0.572360941682157, "cumulativeProbability": 0.9904700716484914 },
      { "tier": 5, "tierGrade": "B", "probability": 0.00921138138950745, "atLeastProbability": 0.009529928351508607, "cumulativeProbability": 0.9996814530379988 },
      { "tier": 6, "tierGrade": "A", "probability": 0.0003096040535107876, "atLeastProbability": 0.0003185469620011565, "cumulativeProbability": 0.9999910570915096 },
      { "tier": 7, "tierGrade": "S", "probability": 0.000008942908490368865, "atLeastProbability": 0.000008942908490368865, "cumulativeProbability": 1 }
    ]
  },
  "analysis": {
    "itemProbability": 0.0002754219076316292,
    "gradeOrBetterProbability": 0.8063509304622342,
    "gradeOrBetterCraftProbability": 0.95298536106221,
    "maxRarityScore": 17.086946819436353,
    "rarityFraction": 0.20834626312343202,
    "maxMaterialRank": 31,
    "maxOrbValue": 15625,
    "factors": [
      { "slot": "material", "name": "copper", "p": 0.056930235239575404, "contribution": 1.244657021650626 },
      { "slot": "slot", "name": "waist", "p": 0.09503239740820735, "contribution": 1.0221283145317657 },
      { "slot": "quality", "name": "-", "p": 0.27790901258927825, "contribution": 0.5560973688242004 },
      { "slot": "gear", "name": "belt", "p": 0.28735632183908044, "contribution": 0.541579243946581 },
      { "slot": "prefix", "name": "-", "p": 0.75, "contribution": 0.12493873660829993 },
      { "slot": "suffix", "name": "-", "p": 0.8499613302397525, "contribution": 0.07060083245690348 }
    ]
  }
}
```

`gradeExpectations` and `analysis` are exact arithmetic over the current tables; `rollsExpected` is a recorded sample.

Exact odds from the current weights:

| Orbs | Candidates | Median grade | B or better | A or better | S | Prefix | Suffix |
| ---: | ---: | --- | ---: | ---: | ---: | ---: | ---: |
| 1 | 1 | F | 5.6e-4% | 1.9e-5% | 5.3e-7% | 25.0% | 15.0% |
| 5 | 1 | F | 4.7e-3% | 1.6e-4% | 4.4e-6% | 25.0% | 15.0% |
| 25 | 1 | E | 0.046% | 1.5e-3% | 4.3e-5% | 25.0% | 15.0% |
| 125 | 2 | C | 0.95% | 0.032% | 8.9e-4% | 43.8% | 27.8% |
| 500 | 5 | C | 21.9% | 0.80% | 0.023% | 76.3% | 55.6% |
| 1,000 | 8 | C | 44.8% | 4.0% | 0.11% | 90.0% | 72.8% |
| 3,125 | 14 | B | 76.7% | 38.7% | 1.3% | 98.2% | 89.7% |
| 5,000 | 18 | B | 85.0% | 47.8% | 3.8% | 99.4% | 94.6% |
| 15,625 | 34 | A | 98.2% | 80.9% | 39.5% | 100.0% | 99.6% |

- Godhair is about 0.8% at the cap, the most any lottery reaches.
- At the guarantee price of each grade from E to S, the lottery reaches that grade or better only 35–57% of the time. The guarantee is the certain route; the lottery is a gamble with better traits.
- `gradeExpectations` is exact arithmetic; `rollsExpected` is a labelled historical sample. Never mix them.
- These odds describe reaching a grade, not winning the exact item.
- Crafts do not target a slot. Your inventory rules decide whether the result is useful.

## Salvage

Destroying an item refunds 10% of its grade's guarantee price, rounded down (`salvage-2`).

```sh
curl 'https://set.world/api/salvage?rolls=<19 numbers>'    # appraise an item (or indexes=)
curl 'https://set.world/api/salvage?tier=6'                # one grade
curl 'https://set.world/api/salvage'                       # the schedule and the sink bound
```

```ts
type SalvageRow = { tier: number; tierGrade: Grade; tierName: string; salvage: number; craftCost: number };
type SalvageSink = {
  schedule: SalvageRow[];                                       // seven rows
  rules: { version: string; rate: number };
  worstReturn: { orbs: number; expectedSalvage: number; returnPerOrb: number };
  strictSink: boolean;
};

type SalvageResponse =
  | SalvageSink                                                 // no parameters
  | (SalvageRow & SalvageSink)                                  // tier=
  | ({ indexes: number[]; salvage: number; score: number; materialRank: number; tier: number; tierGrade: Grade; tierName: string; orbValue: number; material: Material } & SalvageSink);   // rolls= or indexes=
```

The `tier=6` request, answered:

```json
{
  "tier": 6,
  "tierGrade": "A",
  "tierName": "Grade A",
  "salvage": 312,
  "craftCost": 3125,
  "schedule": [
    { "tier": 1, "tierGrade": "F", "tierName": "Grade F", "salvage": 0, "craftCost": 1 },
    { "tier": 2, "tierGrade": "E", "tierName": "Grade E", "salvage": 0, "craftCost": 5 },
    { "tier": 3, "tierGrade": "D", "tierName": "Grade D", "salvage": 2, "craftCost": 25 },
    { "tier": 4, "tierGrade": "C", "tierName": "Grade C", "salvage": 12, "craftCost": 125 },
    { "tier": 5, "tierGrade": "B", "tierName": "Grade B", "salvage": 62, "craftCost": 625 },
    { "tier": 6, "tierGrade": "A", "tierName": "Grade A", "salvage": 312, "craftCost": 3125 },
    { "tier": 7, "tierGrade": "S", "tierName": "Grade S", "salvage": 1562, "craftCost": 15625 }
  ],
  "rules": { "version": "salvage-2", "rate": 0.1 },
  "worstReturn": { "orbs": 15625, "expectedSalvage": 1562, "returnPerOrb": 0.1 },
  "strictSink": true
}
```

Salvage never pays back a craft: a guarantee returns at most 10% of its price, and no lottery spend returns more per orb. `worstReturn` is the best case for the player over every way to craft. Whether disassembly exists is your call.

## Monster drops

Drops fund crafting. They depend on the enemy's average stat and its encounter class.

```sh
curl https://set.world/api/drop/classes
curl 'https://set.world/api/drop?stats=12-14-10-11-13-16-12-14-11&class=elite&seed=7'
```

```ts
type DropClasses = { classes: Array<{ name: 'trash' | 'veteran' | 'elite' | 'boss' | 'world-boss'; multiplier: number }> };

type DropOverride = {
  flat?: number;                           // a non-negative safe integer that replaces the formula
  multiplier?: number;                     // finite, 0..1,000,000
  bonusOrbs?: { min: number; max: number };// 0 ≤ min ≤ max ≤ 1,000,000,000
  guaranteedTier?: number;                 // 1..7 (F..S): also craft an item of exactly that grade
};

type DropResponse = {
  seed: number | null;
  stats: number[];                         // the nine stats sent
  avgStat: number;
  class: string;
  baseDrop: number;
  classMultiplier: number;
  rolledVariance: number;                  // uniform 0.75..1.25, four decimals
  orbs: number;
  override: DropOverride | null;
  guaranteedItem?: Item & { salvage: number };                                                   // only with guaranteedTier
  guaranteedItemCraft?: { requestedTier: number; seed: number | null; budget: number; attempts: number; capped: boolean };
  contentVersion: string;
};
```

The request above, answered at this `contentVersion`:

```json
{
  "seed": 7,
  "stats": [12, 14, 10, 11, 13, 16, 12, 14, 11],
  "avgStat": 12.556,
  "class": "elite",
  "baseDrop": 11,
  "classMultiplier": 10,
  "rolledVariance": 0.7559,
  "orbs": 83,
  "override": null,
  "contentVersion": "4.swpi78HUCtcrZ1Eoi9dipw"
}
```

The arithmetic: `floor(11 × 10 × 0.7559) = 83`.

| Class | Multiplier |
| --- | ---: |
| trash | 1 |
| veteran | 3 |
| elite | 10 |
| boss | 50 |
| world-boss | 250 |

Use `trash` for common mobs, `veteran` for mini-bosses and rare spawns, `elite` for guardians and named enemies, `boss` for end-of-zone bosses and `world-boss` for raid and server events.

`override` is URL-encoded JSON; any other field is rejected with 400. A guaranteed item is crafted on `deriveSeed(seed, 1)` and leaves the orb roll untouched. The multipliers scale the reward, not the enemy's health or damage: threat is your game's math, and `stats` must stay in 8 to 24.

## Stat boosts

```sh
curl 'https://set.world/api/boost/cost?from=14&to=18'
```

```ts
type BoostCost = { from: number; to: number; orbs: number; perStep: Array<{ from: number; to: number; orbs: number }> };
```

```json
{
  "from": 14,
  "to": 18,
  "orbs": 2584,
  "perStep": [{ "from": 14, "to": 15, "orbs": 343 }, { "from": 15, "to": 16, "orbs": 512 }, { "from": 16, "to": 17, "orbs": 729 }, { "from": 17, "to": 18, "orbs": 1000 }]
}
```

Every step's price:

| Step | Orbs |
| --- | ---: |
| 8 → 9 | 1 |
| 9 → 10 | 8 |
| 10 → 11 | 27 |
| 11 → 12 | 64 |
| 12 → 13 | 125 |
| 13 → 14 | 216 |
| 14 → 15 | 343 |
| 15 → 16 | 512 |
| 16 → 17 | 729 |
| 17 → 18 | 1,000 |
| 18 → 19 | 1,331 |
| 19 → 20 | 1,728 |
| 20 → 21 | 2,197 |
| 21 → 22 | 4,096 |
| 22 → 23 | 8,192 |
| 23 → 24 | 32,768 |

`from` and `to` outside 8 to 24 are clamped; `from` must be below `to`. The endpoint prices a stat increase; your game decides whether players can buy one, and Set grants no stat points of its own.

## A schema for your wallet

Set has no wallet. An append-only ledger keeps an economy auditable:

```ts
type OrbLedgerEntry = {
  id: string;
  ownerId: string;
  delta: number;                           // positive for income, negative for spend
  reason: 'drop' | 'exchange' | 'craft' | 'boost' | 'salvage' | 'grant';   // 'exchange': your own resources converted to orbs
  request: string;                         // "/api/craft?orbs=125&seed=11"
  seed: number | null;
  contentVersion: string;
  response: unknown;                       // the full response, so the entry can be audited later
  at: string;
};
// balance = the sum of delta. Charge the effective `orbs` a response reports, never the amount requested.
```

## Building a progression loop

1. **Roll a character** ([Rolling a character](https://set.world/skills/rolling-a-character)). It arrives with 15 items.
2. **Fight to earn orbs.** Your combat rules decide the fight; `/api/drop` prices each kill.
3. **Craft.** Choose a guarantee or a lottery. Equipment does not raise attributes unless your game gives it meaning.
4. **Scale difficulty.** Enemy stats and class set drop prices; you set pacing.
5. **Salvage** what is discarded, if your game allows it.
6. **End game.** A Grade S guarantee costs 15,625 orbs. A 15,625-orb lottery draws 34 candidates: Grade S about 39.5%, A or better 80.9%.

### Pacing crafts across levels

The craft curve sees orbs, not levels. To keep endgame gear rare mid-game, cap the spend per craft by level and offer only guarantees that fit under the cap. For a 60-level game:

```text
maxSpend(L) = min(15,625, round(15,625 × (L / 60)²))     434 at L10, 3,906 at L30, 15,625 at L60
guarantee T allowed when craftCost(T) ≤ maxSpend(L)       A from L27, S only at L60
```

An example model (not a Set rule), recorded under `lottery-3` and `material-grades-3`: average enemy stat rises linearly from 8 at level 1 to 24 at level 60; 40 kills per level at 80% trash, 15% veteran, 4% elite, 1% boss, priced by `/api/drop` (about 26,000 orbs by level 30, 158,000 by level 60).

| Strategy | Any Grade S by L30 | Any A or better by L30 | Any Grade S by L60 |
| --- | ---: | ---: | ---: |
| Keep all 15 slots current (15 even crafts per level), no cap | 0.16% | 5.4% | 3.8% |
| Save everything for one item, no cap | 39% (or 1 guaranteed S) | 81% | — |
| Always spend `maxSpend(L)` per craft | 6.5% | 89% | 93% |

Steady crafting keeps S an endgame story on its own. The cap closes the one shortcut: hoarding a mid-game purse into one S craft or guarantee.

Every formula is per entity, so one hero and an army use the same prices. Before variance, 40 veterans with an average stat of 12 pay `40 × 9 × 3 = 1,080` orbs.

## Related

The derivations and the sink proof: [Algorithms](https://set.world/skills/algorithms), §3 and §8. What crafted gear does in Set's own game: [Derived stats](https://set.world/skills/anima-derived-stats).
