From game-d2i-skills
Generate D2R .d2i item files via natural language for single-player use. This skill should be used when the user asks to "generate a d2i item", "create a d2r item", "give me a Windforce", "generate a legit Shako", "make a 6-socket Grandfather", "find Amazon set items", "make a 7% MF small charm", "search magic prefix", "d2i", or mentions wanting to create Diablo II: Resurrected items for single-player / Hero Editor import. For full character loadouts / builds, use the d2r-loadout skill instead.
How this skill is triggered — by the user, by Claude, or both
Slash command
/game-d2i-skills:d2r-itemsThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generate `.d2i` item files for Diablo II: Resurrected single-player use. Uses `@dschu012/d2s` for binary encoding (D2R version 99 / 0x63).
Generate .d2i item files for Diablo II: Resurrected single-player use. Uses @dschu012/d2s for binary encoding (D2R version 99 / 0x63).
Data source: blizzhackers/d2data (master branch, cached locally via --setup).
gh api "repos/blizzhackers/d2data/commits?per_page=3&path=json/uniqueitems.json" --jq '.[] | "\(.commit.committer.date) | \(.commit.message)"'~/.cache/game-d2i-skills/d2data/_meta.json records fetchedAt timestampindex field) vs in-game display names (from allstrings-eng.json). For example, "Latent Cold Rupture" is stored as "PreCrafted Cold Rupture". When a lookup returns no results, the item may exist under a different internal name — check allstrings-eng.json or search the web to find the mapping.--update-data to re-download from the repoWhen the user uses non-English item names, slang, or abbreviations, do not assume the mapping — verify first:
references/zh-tw-terms.md for Traditional Chinese)Before any search or generation, ensure d2data is cached locally:
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --setup
This downloads the full d2data repository (tarball) to ~/.cache/game-d2i-skills/d2data/. Run --update-data to refresh after a game patch.
The default output format is "raw" (for D2RuneWizard Hero Editor). If the user needs a different tool, set format in ItemSpec JSON:
| Tool | Format | Description |
|---|---|---|
| D2RuneWizard Hero Editor | "raw" (default) | Raw item bytes only (no container header) |
| Other / General | "d2" | Standard D2I container: JM header + uint16 count + item bytes |
Once the user specifies a format, remember their choice for the rest of the session.
Before generating, classify the request:
| Class | Definition | Example |
|---|---|---|
| LEGIT | Stats within game-possible ranges | Windforce with 250% ED |
| MODIFIED | Valid base with impossible stats | 6-socket Monarch (normally max 4) |
| IMPOSSIBLE | Cannot exist in-game at all | +5 All Skills Small Charm |
Always inform the user which class before generating.
"Give me a Windforce" / "幫我做一個暗金頭"
--lookup "<name>" to get code and uniqueId/setIditemCode, quality, uniqueId/setId — omit stats to auto-resolve from d2data (uses max rolls = perfect item)/tmp/d2r-spec.json, Generate — --file /tmp/d2r-spec.jsonAuto-resolve: when the item has a uniqueId or setId, the CLI automatically resolves from d2data (--setup required):
stats empty to auto-resolve (max rolls = perfect item). Provide stats explicitly to override (for modified/impossible items).sockets to auto-resolve from d2data. The resolved value is the item's max socket count. Set sockets explicitly to override.statOverrides: selectively override specific auto-resolved stats without losing the rest. Useful when auto-resolve gives wrong values (e.g., Hellfire Torch class/level).
{"itemCode":"rin","quality":"unique","level":85,"uniqueId":400,"stats":[],"statOverrides":{"83":[4,3]}}
This auto-resolves all Hellfire Torch stats, then overrides stat 83 (item_addclassskills) to [4, 3] → [classId=4 (Barbarian), value=3 (+3 skills)].
Runeword auto-resolve: when runewordId is set, the CLI also auto-resolves:
Minimal runeword spec — only itemCode, quality, level, and runewordId needed:
{"itemCode":"utp","quality":"normal","level":85,"runewordId":59,"stats":[]}
Socket fill strategy: for non-runeword socketed items, ask the user which socketing strategy they prefer before generating. Set socketFill in the spec:
socketFill | Weapon | Shield | Armor/Helm | Use case |
|---|---|---|---|---|
"mf" | Ist (+30% MF) | Ist (+30% MF) | Ptopaz (+24% MF) | Magic Find builds |
"resist" | Um (+15 res) | Um (+22 res) | Um (+15 res) | Survivability |
"damage" | Ohm (+50% ED) | Ber (+8% DR) | Ber (+8% DR) | Physical DPS |
"caster" | Ist | Ist | Ist | Caster builds (use socketedItems for facets) |
"ias" | Shael (+20 IAS) | Shael | Shael | Attack speed |
"cbf" | Cham (CBF) | Cham | Cham | Cannot Be Frozen |
Ask like: "How would you like the sockets filled? MF (Ist/Ptopaz), resist (Um), damage (Ohm/Ber), or something else?"
If the user has specific requirements, use manual socketedItems instead. Each entry needs only itemCode for runes (r01-r33) and gems (gXX). For jewels (jew), also set quality and stats.
{
"itemCode":"uar","quality":"superior","level":85,"sockets":3,"stats":[],
"socketedItems":[{"itemCode":"gpr"},{"itemCode":"gpr"},{"itemCode":"gpr"}]
}
"Find Amazon-exclusive set items" / "Show me all unique polearms"
--search with appropriate filters"Make a 7% MF small charm" / "找 Barbarian 技能魔法前綴"
Magic items need a prefix ID, suffix ID, or both. Use the magic affix search to find the right IDs.
Required level: the game calculates reqLvl = max(base_item_levelreq, prefix_levelreq, suffix_levelreq) using d2data's levelreq field. Use the CLI's --read command to verify the calculated requiredLevel from d2data — this matches the actual game value.
D2RuneWizard Hero Editor reqLvl bug: the hero editor displays incorrect required levels for magic items due to two bugs in its JavaScript: (1) its prefix data array uses different indexing than the game binary, and (2) it uses the prefix data array for suffix lookups too. Ignore the hero editor's "Required Level" for magic items — verify with --read or in-game instead.
Choosing affixes for level-restricted builds: when the user specifies a level range (e.g., "level 10-20"), select affixes whose levelreq fits within that range. Use --max-level in search to filter. Prefer using proper affix IDs over magicPrefix: 0, magicSuffix: 0 so items display correct names (e.g., "Bronze Small Charm of Life" instead of just "Small Charm"). Only use 0, 0 when the level budget is extremely tight (reqLvl must be 1) or the user explicitly requests no affix names.
Steps:
--search --quality magic-prefix or --search --quality magic-suffix with filters:
-q <name> — name substring (e.g., "Shimmering" for resistance prefix)-c <class> — class-specific affixes (e.g., -c bar for Barbarian skill tab prefixes)-t <type> — itype code filter (matches affix itype fields in d2data, e.g., scha for small charms, mcha for medium charms, lcha for large charms, weap for weapons). Not the item code (cm1).--min-level / --max-level — affix level rangequality: "magic", magicPrefix and/or magicSuffix set to the chosen affix IDsstats (no auto-resolve for magic quality). Use the mod info from the affix search to set appropriate stat values.--fileExample: 7% MF Small Charm
{
"itemCode": "cm1",
"quality": "magic",
"level": 85,
"magicPrefix": 0,
"magicSuffix": 290,
"stats": [{"id": 80, "values": [7]}]
}
Note: suffix 290 = "of Fortune" (MF 3-5% on small charms). Search result IDs can be used directly in the spec.
All commands use: npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" <command>
Download d2data JSON files to local cache. Required before --search.
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --setup
Fast fuzzy name search from d2s constants (no d2data cache needed):
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --lookup "windforce"
{"success":true,"query":"windforce","count":1,"results":[
{"name":"Windforce","code":"6lw","id":266,"category":"unique"}
]}
category: unique | set | runeword | armor | weapon | otherid = uniqueId/setId for ItemSpecid = runewordId, code is empty (use base item code)Rich search across cached d2data (requires --setup first):
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --search [filters]
Filters:
| Flag | Short | Description | Example |
|---|---|---|---|
--query | -q | Name substring | -q "windforce" |
--class | -c | Class filter (matches base item categories + set UIClass) | -c amazon |
--type | -t | Item type (helm, sword, shield, belt, etc.) | -t helm |
--quality | unique, set, runeword, base, magic-prefix, magic-suffix | --quality set | |
--min-level | Minimum level requirement | --min-level 40 | |
--max-level | Maximum level requirement | --max-level 60 | |
--limit | Max results (default 50) | --limit 20 |
Result includes name, code, id, category, baseName, levelReq, props (stat summary).
For unique, set, and base results: also includes strReq, dexReq (omitted when 0). These are base item values — ethereal discount is not applied at search time.
For magic affix results, also includes: modCode, modMin, modMax, itemTypes[], classSpecific.
Examples:
# Amazon set items
--search --class amazon --quality set
# Unique helms under level 60
--search --quality unique --type helm --max-level 60
# All items named "Tal Rasha"
--search -q "tal rasha"
# Barbarian skill tab magic prefixes
--search --quality magic-prefix --class bar
# MF-related magic suffixes
--search --quality magic-suffix -q "fortune"
Preview the auto-resolved stats for an item (useful for debugging):
# Unique/set items
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --resolve-stats --quality set --id 80
# Runeword (T1Code properties only)
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --resolve-stats --quality runeword --id 155
# Runeword with rune-in-socket bonuses (--type specifies base item category)
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --resolve-stats --quality runeword --id 155 --type shield
{"success":true,"quality":"set","id":80,"count":9,"stats":[{"id":9,"values":[30]},{"id":7,"values":[60]},...]}
For runewords, the output includes name, runes, and baseTypes fields. The optional --type flag adds individual rune socket bonuses from gems.json (e.g., Spirit Shield +35 cold/lightning/poison resist).
Search for skill names and their numeric IDs (requires --setup):
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --lookup-skill blizzard
{"success":true,"query":"blizzard","count":3,"results":[{"id":59,"skill":"Blizzard","charclass":"sor"},...]}
Generate .d2i file(s) from an ItemSpec JSON. Accepts a single object or a JSON array for batch generation.
# Single item
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --file /tmp/d2r-spec.json
# Single item with format override
npx --prefix "${CLAUDE_PLUGIN_ROOT}/cli" tsx "${CLAUDE_PLUGIN_ROOT}/cli/src/index.ts" --file /tmp/d2r-spec.json --format raw
Single item output:
{"success":true,"outputPath":"/tmp/.../d2r-items/6lw-1708912345000.d2i","fileSize":36,"format":"raw"}
Batch output (when spec is a JSON array):
{"success":true,"count":3,"results":[
{"outputPath":"/tmp/.../cm1-1708912345001.d2i","fileSize":24,"format":"raw"},
{"outputPath":"/tmp/.../cm1-1708912345002.d2i","fileSize":24,"format":"raw"},
{"outputPath":"/tmp/.../cm1-1708912345003.d2i","fileSize":24,"format":"raw"}
]}
The format can be set via --format flag or "format" field in the spec JSON (spec field takes precedence).
When outputPath is set per item in the spec array, each item is written to that path instead of the default timestamp-based name.
{
"itemCode": "6lw", // 3-4 char code (from --lookup or --search)
"quality": "unique", // low | normal | superior | magic | set | rare | unique | craft
"level": 85, // item level (ilvl)
"identified": true, // default: true
"ethereal": false, // default: false
"sockets": 0, // omit to auto-resolve from d2data; set explicitly to override
"uniqueId": 266, // required for unique quality
"setId": 80, // required for set quality
"magicPrefix": 0, // for magic quality (0 = no prefix, 0-indexed row in d2data)
"magicSuffix": 0, // for magic quality (0 = no suffix, 0-indexed row in d2data)
"rareNameId": 0, // for rare/craft quality
"rareNameId2": 0, // for rare/craft quality
"magicalNameIds": [null,null,null,null,null,null], // for rare/craft
"runewordId": 59, // for runeword items
"runewordAttributes": [], // auto-resolved from d2data; provide to override
"socketedItems": [], // auto-resolved for runewords; manual for gems/jewels
"socketFill": "mf", // auto-fill strategy: mf | resist | damage | caster | ias | cbf
"statOverrides": {"83": [4, 3]}, // override specific auto-resolved stats by stat ID
"stats": [], // omit or [] for auto-resolve from d2data (max rolls)
// "stats": [{"id": 17, "values": [250, 0]}], // explicit stats override auto-resolve
"defense": 0, // base defense (armor/shields)
"maxDurability": 40, // max durability (armor/weapons)
"currentDurability": 40, // current durability
"quantity": 0, // stackable items
"outputPath": "", // optional custom path
"format": "raw" // "raw" (default, for D2RuneWizard Hero Editor) | "d2" (JM container)
}
item_maxdamage_percent (id:17, np:2) = [ed, maxDmgBonus]item_singleskill (id:107) = [skillId, level]firemindam (48, np:2) = [min, max]; coldmindam (54, np:3) = [min, max, length]references/common-stats.md for full value format reference| Quality | Value | Required Fields |
|---|---|---|
| low | 1 | — |
| normal | 2 | — |
| superior | 3 | — |
| magic | 4 | magicPrefix, magicSuffix |
| set | 5 | setId |
| rare | 6 | rareNameId, rareNameId2, magicalNameIds |
| unique | 7 | uniqueId |
| craft | 8 | rareNameId, rareNameId2, magicalNameIds |
$TMPDIR/d2r-items/<code>-<timestamp>.d2i$TMPDIR/d2r-items/<loadout-name>/<slot>-<item-name>.d2i (set via outputPath per spec)runewordId — runes, sockets, and runewordAttributes are auto-resolved from d2datareferences/common-stats.md for stat IDs and value formatsreqLvl = max(base_levelreq, prefix_levelreq, suffix_levelreq) using d2data levelreq fields. The --read command calculates this automatically. Note: D2RuneWizard Hero Editor shows incorrect reqLvl for magic items (see Workflow 3 notes)references/common-stats.md for per-stat rangesnpx claudepluginhub vdustr/skill-d2iAudits treasure and magic item placement across campaign modules and character inventories to flag wealth imbalances, rarity mismatches, and loot gaps.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.