wurst-beginner
Getting started with WurstScript for Warcraft 3 map development including project structure, first map, and basic spell creation
Installation
Follow the repository instructions for this skill and your agent. Review the files and dependencies before adding it to your workflow.
View source ↗GuidesSkill instructions
WurstScript Beginner Guide
This guide helps you get started with WurstScript for Warcraft III map development.
Prerequisites
- Install VSCode: https://code.visualstudio.com/
- Install the Wurst extension from the marketplace
- The extension auto-installs the compiler and CLI
Creating a New Project
- Open VSCode command palette (F1)
- Run
>wurst: New Wurst Project - Select a folder for your project
Or use CLI:
grill generate my-wurst-project
Project Structure
my-project/
_build/ # Generated content (don't edit)
.vscode/ # VSCode settings
imports/ # Files to import into map
wurst/ # Your .wurst code files
.gitignore
ExampleMap.w3x # Your terrain map
wurst_run.args # Run configuration
wurst.build # Project configuration
wurst.dependencies # Generated dependency links
Hello World
Create wurst/Hello.wurst:
package Hello
init
print("Hello World")
Run with F1 -> >runmap
Package Structure
Every .wurst file contains exactly one package:
package MyPackage
import SomeLibrary // import other packages
// Global variables
let myGlobal = 42
// Functions
function myFunction()
print("Hello")
// Init block runs on map start
init
myFunction()
Using the Standard Library
The stdlib provides wrappers and utilities. Example:
package SpellExample
import ClosureTimers
import ClosureForGroups
import ClosureEvents
init
EventListener.onPointCast(MY_SPELL_ID) (caster, targetPos) ->
flashEffect("Abilities\\Spells\\Human\\ThunderClap\\ThunderClapCaster.mdl", targetPos)
doAfter(0.5) ->
forUnitsInRange(targetPos, 300) u ->
if u.isEnemyOf(caster)
caster.damageTarget(u, 100)
Coding Conventions
Use Extension Functions
// Jass style (avoid)
local integer id = GetPlayerId(GetOwningPlayer(GetTriggerUnit()))
// Wurst style (preferred)
let id = GetTriggerUnit().getOwner().getId()
Use Cascade Operator
// Instead of
let u = createUnit(player, UNIT_ID, pos, angle)
SetUnitX(u, newX)
SetUnitY(u, newY)
u.addAbility(ABILITY_ID)
// Use cascade
createUnit(player, UNIT_ID, pos, angle)
..setX(newX)
..setY(newY)
..addAbility(ABILITY_ID)
Use Type Inference
// Explicit (verbose)
unit u = CreateUnit(...)
// Inferred (preferred)
let u = createUnit(...)
var health = u.getHP()
Vector Math
Wurst has built-in vector types:
import Vectors
let pos = vec2(100, 200)
let pos3d = vec3(100, 200, 50)
// Operations
let sum = pos + vec2(10, 10)
let scaled = pos * 2
let length = pos.length()
let normalized = pos.norm()
let angle = pos.angleTo(otherPos)
Creating Spells
Basic Spell Structure
package MySpell
import ClosureEvents
import DamageSystem
public constant MY_SPELL_ID = 'A000'
init
EventListener.onCast(MY_SPELL_ID) caster ->
let target = EventData.getSpellTargetUnit()
caster.damageTarget(target, 100, ATTACK_TYPE_MAGIC)
Spell with Timer
package TimedSpell
import ClosureTimers
import ClosureEvents
init
EventListener.onPointCast(SPELL_ID) (caster, pos) ->
var ticks = 0
doPeriodically(0.5) cb ->
ticks++
flashEffect(FX_PATH, pos)
if ticks >= 10
destroy cb
Object Editing in Code
Create WC3 objects without the World Editor:
package MyObjects
import AbilityObjEditing
@compiletime function createSpell()
new AbilityDefinitionFireBolt('A001')
..setName("Super Bolt")
..setTooltipNormal(1, "Super Bolt")
..setTooltipNormalExtended(1, "Deals 100 damage")
..setDamage(1, 100)
..setCooldown(1, 10)
..setManaCost(1, 50)
Building and Running
Run Map (Testing)
- F1 ->
>runmap - Compiles and launches WC3 with your map
Build Map (Release)
- F1 ->
>buildmap - Creates compiled map in
_build/folder
Managing Dependencies
Add a library:
grill install https://github.com/some/library
Update dependencies:
grill install
Debugging Tips
- Use
print()for quick debugging - Use
Log.info(),Log.warn(),Log.error()for structured logging - Check VSCode's Problems panel for compile errors
- Use breakpoints in generated Jass (advanced)
Common Patterns
Event Handling
import ClosureEvents
init
EventListener.add(EVENT_PLAYER_UNIT_DEATH) ->
let dying = GetTriggerUnit()
let killer = GetKillingUnit()
// handle death
Periodic Actions
import ClosureTimers
init
doPeriodically(1.0) cb ->
// runs every second
doAfter(5.0) ->
// runs once after 5 seconds
Data Storage
import HashMap
let unitData = new HashMap<unit, MyData>()
function saveData(unit u, MyData data)
unitData.put(u, data)
function getData(unit u) returns MyData
return unitData.get(u)
Resources
- Full Manual: https://wurstlang.org/manual.html
- Standard Library: https://wurstlang.org/stdlib
- Discord Community: https://discord.gg/mSHZpWcadz
- GitHub: https://github.com/wurstscript/WurstScript
Examples
Read the usage examples in the source repository.
View source ↗Source history
- Indexed on
- 2026-01-20
- Index updated
- 2026-01-26
- Branch
- main
Index and sync dates describe this directory. View the source repository for code history.
GitHub ↗chat Comments (0)
Sign in to join the discussion and leave a comment.
No comments yet. Be the first to share your thoughts!