Build WoW 3.3.5a content with your mouse. Get readable TypeScript out.
A visual content builder for tswow — spells, items, creatures, game objects and quests — plus a WYSIWYG addon designer that draws with your client's real textures.
English · Русский
tswow lets you build World of Warcraft content by writing TypeScript datascripts. That is a great model — and a hard first step if you do not write code.
This studio is a local web app that puts a form in front of every one of those datascripts. You fill
it in, press Generate module code, and it writes a plain, readable, compilable TypeScript
datascript into your module. Nothing is hidden and nothing is locked in: the output is an ordinary
tswow module that builds with build data and travels with you if you stop using the studio.
- Zero dependencies, zero install. One folder, no
npm install. It runs on the Node.js that already ships inside tswow. - Nothing is a black box. The generated code is commented, readable, and meant to be learned from.
- Your hand-written code is safe. The studio only ever regenerates
datascripts/generated/. - Bilingual. Full Russian and English interface, switchable at runtime.
Scope: this is a data tool. Maps, terrain and models are deliberately out of scope — use Noggit and a model editor for those. See What it deliberately does not do.
Pick a recipe, fill in the form, and the datascript on the right updates as you type. Reference fields are checked against the game as you pick them — note the base spell resolving to Hammer of Justice (#853) ✓.
Same flow for every content type: the recipe you choose decides which fields appear, and the emitted code maps to them one-to-one — no hidden state, no magic numbers.
- Put the
tswow-content-studiofolder next to your tswow installation folder — the one that containsmodules/andbin/. - Run
start.bat. - Your browser opens at
http://localhost:8787.
That is the whole setup. There is nothing to install: the studio finds the Node.js bundled with
tswow, and it has no dependencies of its own. If tswow lives somewhere else, set the path in the
interface — it is saved to studio.config.json.
The first launch takes a couple of minutes. This repository ships code only: the game assets
belong to Blizzard and cannot be redistributed. So the studio pulls icons and interface textures out
of your own client on first start — in the background, with progress shown under Settings. FrameXML
sources usually need no extraction at all: tswow unpacks them while building the dataset
(<dataset>/luaxml_source/Interface), and the studio reads them straight from there — faster and
more complete, because the file list inside the client MPQs is incomplete. Its own extraction stays
as a fallback, for an installation whose dataset has never been built. After that everything comes
from the local cache, and a repeat run only fetches what is missing. The same without the studio:
unpack.bat all. Zone maps and parsed models are unpacked on demand, the first time you open a zone
or an appearance.
Running it manually / on a different port
node server/main.mjsSettings live in studio.config.json next to the studio (copy studio.config.example.json to start):
| Key | What it is |
|---|---|
installPath |
Your tswow installation — the folder with modules/ and bin/ |
dataset |
Dataset to read DBCs from, e.g. default.dataset |
port |
HTTP port, default 8787 |
openBrowser |
Open the browser on start |
clientPath |
WoW client, used to extract UI textures and icons |
iconsPath |
Folder of extracted icon PNGs (optional) |
lang |
ru or en |
All of them can also be set from the Settings screen in the UI.
| Required | A working tswow installation (3.3.5a / WotLK) |
Windows — start.bat, mysql.exe and the texture tooling are Windows-only |
|
| Node.js ≥ 18 — already included with tswow, only needed separately if you run it standalone | |
| Optional | A WoW 3.3.5a client — needed for the addon designer's real textures and for icon extraction |
tools/mpqextractor.exe + blpconverter from tswow — for one-click icon extraction |
|
| A running tswow console — enables live world-database search (there is an offline fallback, see below) |
module/
content/ ← builder sources (JSON) — the studio edits these
spells/*.json
items/*.json
...
datascripts/
datascripts.ts ← entry point; the studio adds one import here, once
generated/ ← generated code, regenerated in full
module.ts
spells.ts
items.ts
...
- The source of truth is the JSON in
content/. Keep it in git and ship it with your module — on someone else's machine the studio opens your content as its own. generated/is regenerated in full every time you press Generate module code. Do not edit it by hand; edits are overwritten.- Your own code lives happily alongside in
datascripts.tsand elsewhere. The studio only ever touchesgenerated/.
Then build as usual — in the tswow console: build data (plus build livescripts / build addon
if your module has them).
| Section | Recipes | What's inside |
|---|---|---|
| Spells | 34 | damage, area damage, DoT, healing, HoT, health leech, weapon strike, shield, thorns, stat buff, group buff, run speed, attack speed, slow, crowd control, invulnerability, stealth, dispel, interrupt, taunt, knockback, charge, polymorph, transport, resource restore, resurrection, create item, teach spell, place game object, summon, teleport, passive, passive with a proc, expert mode |
| Items | 8 | weapon, armor, jewelry/cloaks/shields (all with random properties — "…of the Bear"/"…of the Eagle"), consumables, materials, quest items, key, book/letter with pages, expert mode |
| Creatures | 6 | enemy (with loot, loot groups and combat behavior), vendor (special price: honor, arena, tokens; stock and restock), quest giver, trainer, NPC with gossip, expert mode — all with "appears only during a game event" |
| Game objects | 5 | chest with loot, decoration, button/lever, door, quest object; lock (key item, lockpicking, mining, herbalism), game event binding |
| Quests | 4 | kill creatures, bring items, deliver a message, expert mode |
| Crafting | 2 | recipe for an existing profession (reagents, difficulty, crafting station, auto-learn by rank), new profession with ranks |
| Achievements | 1 | 17 kinds of condition (kill, complete a quest, reach a level, obtain an item, reputation, emote…), points, hidden flag, reward with title/item/letter |
| Classes & gear | 7 | class starter kit (bag items, equipped items, level-1 spells, per race), talent tree, gathering spot, gem, enchant, glyph, mount |
| World & events | 3 | scheduled game event (yearly / weekly / daily / hourly / one-off), fishing in a zone (catch, groups, skill), flight path (two pads, waypoints, price, mount, flight masters) |
| Everything else | 84 registries | titles, factions, reputation, item sets, enchants, gems, glyphs, mounts, companions, currencies, game events, holidays, zones, triggers, graveyards, GM teleports, spawn groups, transports, creature texts, mail templates, languages, all 30 game object types… |
The Everything else section is not hand-written — it is built from the types of your installed
tswow version. The studio reads every std.* registry, its entry class and all editable fields
(texts, numbers, enums, masks, references, nested substructures, lists), and the generated code
mirrors the field path exactly: TITLES_HERO.Text.Male.enGB.set("…"). The same is true of spell
expert mode: the effect and aura catalog is read from
bin/scripts/wow/wotlk/std/**/*.d.ts, not hard-coded, so it always matches your tswow version.
The 🖼️ Interface (addon) section is a WYSIWYG window editor for the game client, in two modes.
Assemble a screen with the mouse: panels with backgrounds and borders (presets "Dialog", "Tooltip", "Parchment", or your own files), texts using standard font objects, images with texcoord cropping, buttons (client templates or your textures), checkboxes, edit boxes, status bars, sliders, scroll areas, item slots, dropdowns, 3D model frames. Widgets drag, resize by the corner, nudge with arrow keys, and anchor to the parent or a sibling — nine anchor points, Y going up, exactly like WoW.
Behavior without writing code. A button's What the click does: close the window, show/hide a
widget, open another screen of the module, write to chat, cast a spell / use an item / run a macro
(via SecureActionButtonTemplate, so it works in combat), or send a packet to the server. Bars and
texts get Live data: player/target health and resource, experience, name, level, zone, money, time
— the window subscribes to the events and updates itself.
Conditions, WeakAuras-style. Any widget gets an "if … then …" list: in combat / out of combat, has target / hostile target, health or resource below %, has a buff or debuff by name, zone, mounted, resting, dead, in party / raid / instance → show, hide, recolor, set transparency.
A 1024×768 canvas where the stock Blizzard windows — player and target portraits, focus, party, runes/totems, minimap, buffs, action bars, micro menu, bags, chat, cast bar, timers, quest tracker — are drawn as they are in the client, from the FrameXML tree with real textures, fonts, sample icons, portraits and bar colors.
The list on the left is not limited to those thirty windows: the “Add a client window…” button
opens a search across all 270 top-level FrameXML windows — merchant, bank, mail, quest log, the
achievement window and the rest. An added window is stored in the draft itself, is drawn on the
canvas only while selected (otherwise it would cover the whole HUD), and is removed with the bin
button next to it. Windows from load-on-demand Blizzard addons (Blizzard_AchievementUI and the
like) do not exist yet when you enter the world, so the studio also listens for ADDON_LOADED —
without it the tweak would silently fail to apply.
Drag to move (ClearAllPoints + SetPoint + SetUserPlaced), set scale and transparency, hide what
you don't want (the frame is reparented to a hidden parent, so Blizzard code cannot bring it back),
swap health/mana bar textures. Then go deeper into window parts: click a portrait, border, label,
button or bar and change its texture, vertex color, desaturation, font, size, outline, offset
(Alt+drag), size, transparency or visibility. The generated code applies edits on entering the world
and installs hooksecurefunc — with recursion guards — on the methods Blizzard uses to restore its
own values (SetTexture, SetVertexColor, SetStatusBarColor, SetFont, Show…).
You can also add elements the client does not have: a micro-menu button
(MainMenuBarMicroButton, 28×58, seated right after the help button like the stock ones), a bar
backdrop segment to extend the art under it, a round icon button, or a label.
The studio emits a normal tswow addon in TypeScript — same path as a hand-written one
(addon/addon.ts → build addon → Lua in the client patch):
addon/generated/ui/<Name>.ts— the layout.create<Name>(handlers)builds the widgets with the stock WoW API (CreateFrame,SetPoint,SetBackdrop, button templates) and returns them by name (ui.okButton,ui.progress), plusshow/hide/toggle. Regenerated in full.addon/<screen>.logic.ts— yours, created once and never overwritten. Click/input/slider handlers with annotated stubs, a/namechat command, and optional server-talk stubs (CreateCustomPacket/OnCustomPacket).
Layout and behavior stay separated: design in the studio, logic in code, neither fighting the other.
Generate addon writes the files and wires them into addon/addon.ts; Check addon runs tsc
against addon/tsconfig.json — the same config build addon uses.
Client textures — how the real WoW look gets into the preview
The Extract client textures button reads the file lists out of your client's MPQ archives and
extracts Interface\* — excluding icons, which are handled separately, and world maps and loading
screens — together with the fonts, into cache/ui. After that the preview draws real client borders,
buttons and fonts, and the texture picker gains "Popular", folders and search.
Your own images are BLPs in modules/<module>/assets/Interface/…, referenced by the same kind of path.
The Modify the default UI canvas needs the FrameXML sources: the studio takes them from
<dataset>/luaxml_source, or extracts them from the client itself if the dataset is not built yet.
A client subtlety the studio handles for you — anchors vs. SetWidth
If a window part's size comes from its anchors — stretched across the parent, or pinned by two
corners — then SetWidth is silently ignored by the client. The studio detects this, warns you in
the properties panel, and keeps a single anchor in the generated code so the size actually applies
and position is computed from that anchor.
Why tswow TypeScript and not plain Lua?
The addon lives in the same module, is built with the same command, has its WoW API types checked by the compiler, and gets the server link (packets, livescripts) as an existing tswow mechanism. Lua is still what comes out the other end.
Spell card — like Spell Editor, no database needed
Every spell ID in the interface is clickable, and every row in the spell picker has an ⓘ. The card
shows everything the DBCs know: the description with macros expanded ("deals 14–22 damage… over
4 sec" instead of "$s1… $d"), school, cast time, cooldown, cost, range, duration, level, stacks,
effects (type, aura, value, targets, period, radius, what it triggers — with a link to follow) and
attributes.
Supported macros: $s $m $M $o $d $t $a $h $n $u $x $e $q $b $i,
cross-spell references ($12345s1), ${…} expressions, $<…> variables with condition chains, and
$l… plurals.
Finding content — three sources, with an offline fallback
- Spells, icons and zones are read straight from the DBCs of the selected dataset. No database needed.
- Items, creatures, game objects and quests are searched in the world database via
bin/mysql/mysql.exe. Credentials come from the installation's own config —node.conf(Database.WorldDest/WorldSource,Database.Prefix), database name<module>.<dataset>.world.dest, built exactly the way tswow builds it. This works while the tswow console is running, since that is what brings MySQL up. Localized names are read from the*_localetables, and search matches both localized and English names. - If the tswow console is closed, the studio reads the TDB dump (
bin/TDB_full_world_*.sql) itself — the way Spell Editor reads DBCs without a server. The first run builds an index (about two seconds, cached incache/); after that, search and take as a draft work fully offline. Honest limitation, which the studio also states in the list: the dump does not contain your modules' content. - Icon images appear once you point Settings at a folder of extracted PNGs (file name = icon ID
from
SpellIcon.dbc). Without it the icon picker still works, by name.
Modifying existing entries instead of creating new ones
Everything else has a Modify existing toggle: pick a registry, find an entry from the game (Fireball, Linen Cloth, a wolf) and fill in only what you want to change — everything else on the entry is left alone. Spell effects are handled separately: either just the value ("damage 500 instead of 20"), or the effect redefined in full.
- Reference checking. Next to any entry ID, the studio prints its in-game name — "Fireball (#133) ✓" — or warns that no such entry exists. Check compilation adds a module-wide summary of broken references.
- Entries reference each other. "My entries" come first in every picker, so a quest can point at a
wolf from the same module and the code gets
NPC_WOLF.IDwith the rightimportbetween files. Real IDs are assigned when tswow builds; you never type them. - Take from the game as a draft. Spells, items and creatures have a button that opens an existing entry with all its values filled in. Edit, save as your own.
- Starter kits. Village (an elder with gossip and a quest, a vendor, a trainer, a guard, wolves, a chest), Caster class, Profession with recipes, Boss with mechanics — several linked entries in one click.
- Plain-language explanations. For the 160 most-used effects and auras the studio carries a
human-readable explanation of what the effect does and what its value means — shown in the picker
(search matches it, so "shield" finds
SCHOOL_ABSORB), in the effect card, and as a comment above the effect in the generated code, so the file reads as a lesson. - Auto-descriptions. Generate description from settings on a spell; if the description is empty
the generator fills it in with
$s1/$dmacros the client will substitute. - NPC gossip that does things. A reply option can offer a quest, teleport the player, cast a spell on them or hand over an item — all through stock SmartScript.
- Creature behavior without code. when → what → to whom rules: say a line on entering combat; every 12 seconds cast at a random enemy; at 30% health summon help; at 15% flee; on death yell; heal a wounded ally. Stock TrinityCore SmartScript, defined as data — no server programming, no restart.
- Spell ranks. A "level → power as % of rank 1" list; the studio creates the chain, links it, and adds every rank to the trainer as one list.
- Patrol paths for creatures: points with pauses, walk/run/fly.
- Export / import a module's content as a single JSON, copy an entry to another module, version history (up to 20 per entry) with rollback.
- A "what next" reminder after generating: which
buildcommands to run, what to restart, and a check that the module is actually attached to the dataset (Dataset.Modules). - Search across your own content, empty-name highlighting,
Ctrl+Sto save,Ctrl+Enterto check.
Check compilation runs the TypeScript compiler from your tswow installation across the module's
datascripts and reports errors in the interface language, pointing at the object that has the
problem. It is the same compiler build data will use, so "check passed" means the module will build.
It does not run the data build: it writes neither DBC nor SQL, and is safe to use while the server is running.
Maps, terrain and models are not the studio's job — Noggit and dedicated model editors exist for that. The studio deals with data: spells, items, creatures, game objects and quests.
- The game itself caps things, and the studio warns you in advance: a spell cannot have more than three effects, an item more than ten stats and three sockets, a quest more than four objectives.
- In the universal editor, lists with complex arguments (achievement conditions, talents, path points) are displayed but must be filled in by hand in code — the studio says so under the field.
- Outside datascripts and therefore outside the studio: server-side logic (livescripts), new classes and races with their client-side patches, and maps/models/icons as files.
- Checking compilation is not a substitute for running. Test in-game logic on a live server.
server/ local HTTP server, no framework
catalog/ reads tswow's own .d.ts types → registries, entities, fields
codegen/ JSON → TypeScript datascript emitters (spell, item, creature, addon, classkit…)
framexml*.mjs parses the client's FrameXML tree for the default-UI editor
dbc.mjs DBC reader sql.mjs / tdb.mjs world DB + offline TDB dump index
textures.mjs MPQ texture extraction
shared/ code used by both sides
recipes/ recipe definitions — the forms and their meaning
i18n/ keys.json + en.json (key = the Russian source string)
web/ browser UI, plain ES modules
app.mjs shell forms.mjs recipe forms
designer.mjs addon designer blizzard-*.mjs default-UI editor
tools/
i18n-extract.mjs collects translatable strings; --check lists what's missing
No framework, no bundler, no dependencies — the server, the DBC reader, the TDB SQL indexer, the FrameXML parser and the TypeScript generator are all hand-written.
node server/main.mjs # run
node tools/i18n-extract.mjs # collect translatable strings
node tools/i18n-extract.mjs --check # list untranslated stringsTranslations. shared/i18n/en.json maps the Russian source string to its English text. Adding a
language means adding a dictionary next to it. UI language is switched with the 🌐 button in the
header, or "lang" in studio.config.json; it covers the interface, hints, messages and the
comments in generated code — your own content (names, descriptions, entry names) is never touched.
Issues and pull requests are welcome. Useful things to know:
- Plain ES modules everywhere,
.mjs, no build step. Open a file, edit it, restart the server. - A new content type is usually a recipe in
shared/recipes/plus an emitter inserver/codegen/. - New user-visible strings should be run through
node tools/i18n-extract.mjsso translators see them. - Please do not commit
cache/,studio.config.jsonor extracted client assets — see.gitignore.
- tswow — the framework this is built for.
- TrinityCore — the server core underneath.
- StormLib by Ladislav Zezula (MIT) — MPQ archive
reading.
tools/mpqextractor.exeis a small command-line wrapper around it, used to extract client textures and icons. Full notice in THIRD-PARTY-NOTICES.md.
MIT © 2026 Alexandr (MrGreenCheezz)
tools/mpqextractor.exe is redistributed under StormLib's MIT license — see
THIRD-PARTY-NOTICES.md. No World of Warcraft game data ships in this
repository.
This is an unofficial tool for private-server development. World of Warcraft and the assets it reads from your own client are the property of Blizzard Entertainment. No game data is redistributed here.

