# Dragonwilds Crafting Atlas > An interactive crafting-dependency map of every item in RuneScape: Dragonwilds — > 1,983 nodes and 4,912 edges of recipes, stations, materials, skills and spells, > plus a quest layer (37 quests and 21 mounts wired region → quest → reward), > scraped from the Dragonwilds Wiki and rendered as one navigable graph. Static site, > no backend — the front end is bundled by Vite into plain static files. ## Overview The Atlas answers one question: *"What do I need to do to craft this thing from what I have now?"* Pick any item and the graph walks dependencies backwards to raw materials, the stations you must build, and the skills you must train. The page itself (`index.html` + `src/*.js`, bundled by Vite) is a client-side application built on Cytoscape.js; there is no server and no API — everything an agent or scraper could want lives in the static data files linked below. The dataset is regenerated from [dragonwilds.runescape.wiki](https://dragonwilds.runescape.wiki) by scripts in the repository, so the site is fully reproducible from source. Interactions worth knowing about: click a node to open its codex panel (recipes, facilities, skills, a from-nothing Gather/Build/Train plan, and a **Live map ↗** hand-off for gatherables — the atlas has regions but no coordinates, so that opens the Wyrmwatch map pre-filtered to the item's own markers), Shift+Click to isolate its crafting tree, type to search; the ⚙ panel offers force-directed / dagre / ELK layouts with snapshot save/restore; scripted guided tours live in `src/tours.js` (deep-link `?tour=robes`, `?tour=outputs`, `?tour=inputs`). Every item also has a stable URL name — the snake_case form of its display name — so `#/ash_logs` opens that item's codex panel, `#/dragon_slayer` opens a quest and `#/ash_logs/iron_sword` opens the crafting path between the two (rules in `src/routing.js`; the fragment never reaches the server). Every graph option is settable from the query string too — `?layout=elk-layered-wide`, `?cats=food`, `?links=0`, `?starter=0`, `?iso=iron_sword&isodir=up&isodepth=2`, and the rest of `OPTION_PARAMS` — and a value from the URL overrides the visitor's stored setting for that session without ever being saved, so a link reproduces a view exactly; the address bar is kept in step as options change. A page with no options opens on the **beginning of the game**, not the whole map: the tutorial quest, the region it is set in (Temple Woods) and the division above it (Brynmoor), everything found in that region, every skill node, and the region's dead ends — the gatherables, which have no recipe (41 nodes). So "Nodes drawn: 41 of 2123" from `atlas_get_state` means the starting view is on, and that tool says so in a line of its own; a visitor leaves it by clicking a kind row, typing in the search box or choosing Show everything, and `?starter=0` asks for the whole map from a link (`atlas_set_filters` also leaves it, since asking for one kind is the same request a kind row makes). All data is non-commercial fan content used under the [RuneScape Fan Content Policy](https://www.jagex.com/en-GB/legal/fan-content). ## Agents (WebMCP) The page registers callable tools through [WebMCP](https://developer.chrome.com/docs/ai/webmcp) (`document.modelContext.registerTool`) wherever the browser exposes that API, so an agent can ask for an answer instead of scraping the DOM. Fourteen tools, each a thin adapter over what the site's own controls do: - `atlas_search_items` `{query, limit?}` — find any item, station, skill, region, quest or mount by partial name. - `atlas_get_item` `{item}` — one node's codex: kind, recipes (inputs, station, skill, XP), what it is used to make, where it is found, owned state. - `atlas_map_link` `{item}` — where exactly it is gathered: a link to the live Wyrmwatch map filtered to that item's marker type and framed on them, or an explanation when the map draws nothing of its kind. - `atlas_get_plan` `{item, from_owned?}` — what to gather, build and train, plus the critical chain. - `atlas_find_path` `{from, to}` — the shortest crafting route between two nodes, as ordered steps. - `atlas_get_region` `{region}` — what a region or territory holds and the quests set in it. - `atlas_get_quest` `{quest}` — a quest's region, where to start, rewards and the mounts it unlocks. - `atlas_get_owned` `{}` — the user's owned-item ledger. - `atlas_get_state` `{}` — the current view: selection, isolated tree, highlight, kind/link filters, layout, counts. - `atlas_focus_item` `{item}` — open a node's codex and centre the map on it. - `atlas_isolate_tree` `{item, direction?, depth?}` — collapse the map to one item's crafting tree. - `atlas_highlight_links` `{item, direction?, reset?}` — highlight what an item is made from or made by, one level per call. - `atlas_set_owned` `{item, owned}` — mark an item owned or unmark it. - `atlas_set_filters` `{kinds?, links?, dead_ends?}` — show or hide node kinds, link layers and dead ends. The read-only tools carry `readOnlyHint`; the five that move the view or the ledger do not. Without the API the site is unchanged (no tools, no extra requests). The same tool set is on `window.DW_WEBMCP` with an `execute(name, args)` helper, which is how the acceptance suite exercises every one of them. ## Data The machine-readable core of the site. `data.json` is authoritative; the graphml and cyjs files are exports of it for desktop graph tools. - [data.json](https://rudeboy.dev/dragonwilds-crafting-atlas/data.json): the full dependency graph (~3 MB). `nodes[]` carry `id`, `name`, `kind` (material, station, tool, weapon, armour, food, drink, potion, spell, skill, trinket, ammo, resource, mount, implicit, other) and a `wiki` URL; `edges[]` run `from` (ingredient) → `to` (product) with `qty`, `facility`, `skill` and `xp` fields. The graph is a DAG except for three deliberate metal-recycling loops (Bronze/Silver/Gold Bar ⇄ Leaf); a cycle audit lives at `scripts/audit-cycles.mjs`. - [found-in.js](https://rudeboy.dev/dragonwilds-crafting-atlas/found-in.js): per-region gather annotations for Ashenfall's populated regions — which items are found where and how they are gathered, mined from the item pages' prose. - [map-links.js](https://rudeboy.dev/dragonwilds-crafting-atlas/map-links.js): the live-map hand-off — for each atlas node the Wyrmwatch map draws, the marker type key(s) it is drawn under and the `#view=,,&filters=…` fragment that frames them (`window.DW_MAP_LINKS`, with the source page, reference snapshot and attribution). The atlas itself has no coordinates; this is the join, made once at build time and filtered strictly by name. - [region-resources.js](https://rudeboy.dev/dragonwilds-crafting-atlas/region-resources.js): the other direction — what each of Ashenfall's regions and territories holds, taken from the `==Resources==` section of its own wiki page (`{ region: { itemId: [gather method] }, stubs: [region] }`, `window.DW_REGION_RESOURCES`; `stubs` names the pages with no `==Resources==` heading yet). The map unions this with found-in.js into its green region hubs, and every canonical region gets a hub whether or not either source names it. - [quests.js](https://rudeboy.dev/dragonwilds-crafting-atlas/quests.js): the quest layer — every quest on the wiki's Quests page with its type, region, "Where to Start" line and reward items (`window.DW_QUESTS`). - [mounts.js](https://rudeboy.dev/dragonwilds-crafting-atlas/mounts.js): the mount layer — per mount its base type, the quest(s) that unlock it, how to obtain it and its lore (`window.DW_MOUNTS`). - [data.graphml](https://rudeboy.dev/dragonwilds-crafting-atlas/data.graphml): the same graph as typed GraphML, importable into yEd, Gephi, NetworkX, igraph or Cytoscape. - [data.cyjs](https://rudeboy.dev/dragonwilds-crafting-atlas/data.cyjs): Cytoscape.js JSON export with a baked-in layered seed layout. ## Documentation Repository documentation, served raw from GitHub: - [README](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/README.md): what the Atlas is for, how to run it locally, and the Cytoscape export workflow. - [CONTRIBUTOR.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/CONTRIBUTOR.md): the code — how `src/` + `public/` are wired and built, the conventions, the three test layers, the PR checklist. - [CONTRIBUTOR-DATA.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/CONTRIBUTOR-DATA.md): the data — correct a row in the app and ship it as a pull request end to end (edit → export → `scripts/apply-edits.mjs` or `scripts/open-edits-pr.mjs` → PR), refresh from the wiki, or answer the location checklists. The app carries the visitor-facing half of this loop as an in-app window; this file is the developer's copy. Also served beside this file, as [`CONTRIBUTOR-DATA.md`](https://rudeboy.dev/dragonwilds-crafting-atlas/CONTRIBUTOR-DATA.md) and [`CONTRIBUTOR.md`](https://rudeboy.dev/dragonwilds-crafting-atlas/CONTRIBUTOR.md). - [PLAN.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/PLAN.md): the change log — every shipped increment and what is planned next. - [DESIGN.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/DESIGN.md): the design system — colour tokens, the Cinzel/Alegreya type pairing, spacing, component reference. - [PRODUCT.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/PRODUCT.md): product intent — audience, success criteria, non-goals, performance budget, legal constraints. ## Contributing Fixes can be made **in the app**: the ✎ in an item's codex panel opens an edit form (fields and links), ⚙ → **Your data edits** lists every difference against the bundled dataset, and **⤓ Export edits** downloads them as `dragonwilds-edits.json`. The app's **?** help → *How to send a fix in* opens a window with the same loop in plain language (fix → check the diff → export → send); a visitor without a clone sends the export through the repository's [**Data fix**](https://github.com/skamansam/dragonwilds-crafting-atlas/issues/new?template=data-fix.yml) issue form, whose file box takes the JSON directly. `node scripts/open-edits-pr.mjs dragonwilds-edits.json` merges that file into the dataset, branches, commits, pushes and opens the pull request (it takes the same overlay `scripts/apply-edits.mjs` does, and shares its merge logic); `scripts/apply-edits.mjs` remains the apply-only step. The dataset also has known gaps, tracked as hand-editable checklists that keep human knowledge outside the generated pipeline: - [needs-locations.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/docs/checklists/needs-locations.md): 233 items with no found-in region on the wiki — each row wants a location. - [unknown-source.md](https://raw.githubusercontent.com/skamansam/dragonwilds-crafting-atlas/main/docs/checklists/unknown-source.md): 435 rows whose source is described only vaguely (e.g. "looted from metal salvage hotspots") — each wants a concrete region. A round-trip script (`scripts/checklist-csv.mjs`) converts these to CSV and merges edits back; the merge is idempotent and self-heals wiki links against `data.json`. ## Optional - [atlas-style.xml](https://rudeboy.dev/dragonwilds-crafting-atlas/atlas-style.xml): Cytoscape Desktop vizmap style mirroring the web Atlas' node colours and shapes. - [layout-worker.js](https://rudeboy.dev/dragonwilds-crafting-atlas/layout-worker.js): the Web Worker that runs heavy layout computations off the main thread. - [RuneScape: Dragonwilds Wiki](https://dragonwilds.runescape.wiki): the upstream source of every fact in the dataset.