A Chrome extension (Manifest V3) that scrapes D&D character data from D&D Beyond, DiceCloud, and Shieldmaiden, stores it in chrome.storage.sync, and exposes it to Shieldmaiden via chrome.runtime.sendMessage.
background.js— service worker; listens for external messages and responds with stored characters/versionindex.html— popup UIextension/— popup scripts (loaded as ES modules)popup.js— tab/step navigation, sync button injectionmy-characters.js— character list rendering, filtering, searchdata.js—getCharacters()/getStorage()helpers (async, useawait)functions.js— shared helpers (syncCharacter, navigate, tabSelect, etc.)
content/— per-source content scripts (concatenated by gulp before injection)dndbeyond/,dicecloud/,shieldmaiden/— scraper + content script per sourcemodels/character.js— shared character model
common/—store.js,util.jsshared by content scripts
Gulp copies/concatenates src/ into build/base/, which is the directory loaded as the unpacked extension. Never edit files in build/ directly.
Content scripts are concatenated: common/store.js + common/util.js + [source files] → build/base/content/<source>_character.js
npm run gulp # clean build + watch
npm run gulp build # one-off build
npm run gulp export # bump manifest version from package.json, build, zip to dist/Load build/base as an unpacked extension in Chrome.
- Do not include Claude co-author lines or any mention of Claude in commit messages
- All popup/extension JS uses ES modules (
type="module") getCharacters()is async — alwaysawaitite.currentTargetmust be captured before anyawaitin event handlers (browser nulls it after dispatch)- Character sources:
"DnDBeyond","DiceCloud","Shieldmaiden"(also"HarmlessKey"legacy alias for Shieldmaiden) - Storage keys are character URLs;
"config"key is excluded when fetching characters externally_connectableinmanifest.jsoncontrols which domains can message the extension