A collection of community-generated macros utilizing both free and premium asset libraries to animate Foundry VTT.
Join the Discord channel! Learn Sequencer and share your own creations!
Want to Contribute? We'd love to have you! There are (at least) two ways to contribute to this project:
- Post your own Sequencer animations to the Discord and request integration!
- Create a PR following the current coding standards:
create/playfunctions exportedDEFAULT_CONFIGused as the base configuration- Test the animation with token rotation
- (If integrating with AA) standardized arguments for
create/playfunctions
Hate following coding guidelines? Me too! I'd recommend using an AI agent to help. The code here isn't a case of life or death; it's a fun side project that shouldn't take up much of your time, please don't feel you need to spend an entire day getting a PR in. Skills have been written to help enforce the coding guidelines, just ask the agent to clean up your code following the discord to module and style guide skills.
Downloading Visual Studio Code and/or an agentic IDE such as Google's Antigravity to help modify code.
Want this localized into your native language? I don't entrust that to AI - I need native speaker help! Submit a PR and I'll be happy to give a mild vetting process and approve it.
- Eskiemoh / eskie (@.eskie)
- Bakana (@bakanabaka)
- DerKriegs (@derkriegs)
- Gornetron (@nefin)
- Doomrule (@doomrule)
- Mia Del'Mori (@.tranquilite)
- Akane (@yamiakane)
- Brazilian Portuguese
- Kharmans (@kharmans)
- Spanish
- Cerbe (@cerbe_)
- A wide variety of animations!
- Automated Animations integration!
- User-facing API for macro support!
- Highly customizable variants!
- Automated tile-based trap system!
EMP requires the following modules to be installed and active:
| Module | Purpose |
|---|---|
| Sequencer | Core animation playback engine |
| socketlib | Multi-client socket communication for synced effects |
The following modules are optional but unlock additional features when installed:
| Module | What It Enables |
|---|---|
| Automated Animations | Interface with Automated Animations to play effects using AA's system. |
| Eskie Effects (Patreon) | Additional premium effect assets designed specifically for EMP (or the free variant) |
| Jinker's Animated Art Pack | Animated asset library used by select effects |
| JB2A (Patreon) | Large library of high-quality animated assets used by many EMP effects (or the free variant) |
| Boss Loot Assets (Patreon) | Premium asset pack used by select effects (or the free variant) |
| Tagger | Tag-based tile and token lookup; used by some trap and movement effects |
| Token Attacher | Attaches tokens to tiles for movement-based trap and tile effects |
| Monk's Active Tile Triggers (MATT) | Required for the Traps API. Automates trap playback when tokens enter tiles |
All API methods are available from any Foundry VTT macro or the browser console (F12). There are four top-level namespaces:
| Namespace | Description |
|---|---|
eskie.effect |
Token and template-based spell/ability animations |
eskie.overlay |
Canvas-wide scene overlays |
eskie.showcase |
Long-form cinematic sequences |
eskie.traps |
Automated tile-based trap system |
Quick exploration: Run
console.log(eskie)in the browser console to browse everything available.
Token and template-based animations for spells, abilities, and conditions. Most effects accept a token (or array of tokens) as the first argument, with an optional config object for customization.
Common API shape:
| Method | Description |
|---|---|
create(token, [...], config) |
Builds and returns a Sequence without playing it |
play(token, [...], config) |
Builds and immediately plays the Sequence |
stop(token, config) |
Stops or reverses any persistent effects |
default_config |
The default configuration object for that effect |
let token = _token;
let target = Array.from(game.user.targets)[0];
// Play a persistent aura on a token
await eskie.effect.rage.play(token);
await eskie.effect.rage.stop(token);
// Play a targeted effect (caster → target)
await eskie.effect.divineSmite.play(token, target);
// Customize with a config object
await eskie.effect.banishment.play(token, { color: 'purple' });
await eskie.effect.banishment.stop(token, { color: 'red' });
// Build a Sequence manually without playing it
const seq = eskie.effect.hex.create(token, target);
seq.play();Sample effects:
| Key | Description |
|---|---|
eskie.effect.rage |
Barbarian Rage aura |
eskie.effect.banishment |
Banishment shimmer (supports color option) |
eskie.effect.hex |
Hex curse beam to target |
eskie.effect.magicMissile |
Magic Missile projectile burst |
eskie.effect.divineSmite |
Divine Smite radiant flash |
eskie.effect.mistyStep |
Misty Step blink teleport |
eskie.effect.mirrorImage |
Mirror Image ghostly duplicates |
eskie.effect.possession |
Possession overlay effect |
eskie.effect.incorporeal |
Incorporeal movement shimmer |
eskie.effect.callLightning |
Call Lightning storm bolt |
eskie.effect.chainLightning |
Chain Lightning arc |
eskie.effect.disintegrate |
Disintegrate death effect |
eskie.effect.faerieFire |
Faerie Fire outline glow |
eskie.effect.armorOfAgathys |
Armor of Agathys frost shield |
eskie.effect.animateDead |
Animate Dead rise effect |
eskie.effect.wingsV2 |
Animated wings attachment |
eskie.effect.tokenMask |
Token destruction (burn, shatter, tear, smoke) |
eskie.effect.stepOfTheWind |
Step of the Wind (jump, move sub-keys) |
eskie.effect.emote |
Floating emote display above a token |
eskie.effect.shuffle |
Shuffle multiple tokens' positions simultaneously |
Run
console.log(eskie.effect)to browse all 95+ available effects.
Canvas-wide scene overlays that affect all players simultaneously.
| Key | Description |
|---|---|
eskie.overlay.cinemaBars |
Black letterbox bars at the top and bottom of the scene |
eskie.overlay.blur |
Scene-wide blur / drunk effect targeting specific players |
// Cinematic letterbox
await eskie.overlay.cinemaBars.play();
await eskie.overlay.cinemaBars.stop();
// Apply a blur to specific users (by name)
let users = game.users.map(u => u.name);
await eskie.overlay.blur.drunk.play(users);
await eskie.overlay.blur.drunk.stop(users);Long-form cinematic sequences for dramatic, narrative moments.
| Key | Description |
|---|---|
eskie.showcase.attackAttack |
Attack on Titan-style dramatic combat sequence |
eskie.showcase.mobPsycho |
Mob Psycho 100-style psychic burst sequence |
eskie.showcase.sunHaloDragon |
Sun halo dragon cinematic reveal |
eskie.showcase.vnDialog |
Visual Novel-style dialog boxes for narrative scenes |
await eskie.showcase.attackAttack.play(token);
await eskie.showcase.mobPsycho.play(token, target);
await eskie.showcase.sunHaloDragon.play(token);
await eskie.showcase.vnDialog.play({ speaker: token, text: 'Hello, adventurer!' });Automated tile-based traps powered by Monk's Active Tile Triggers. Once set up, traps fire automatically whenever a token enters a designated trigger tile — no macro required.
⚠️ Requires: Monk's Active Tile Triggers must be installed and active to use the setup wizard.
// Opens an interactive dialog to pick a trap type and walks you through setup
await eskie.traps.setup();The wizard will:
- Ask which trap type to configure
- Ask you to select Trigger Tile(s) on the canvas — the tiles tokens step on to activate the trap
- Ask you to select Trap Tile(s) — where the effect plays (or launches from)
- For Fire and Projectile traps: ask for Target Tile(s) — where the effect lands
- Automatically write all MATT configuration and runcode to each tile
Each trap can also be set up independently:
await eskie.traps.fire.setup();
await eskie.traps.pitfall.setup();
await eskie.traps.projectile.setup(); // prompts for Arrow, Dart, or Javelin
await eskie.traps.spike.setup();Traps can be triggered manually from a macro without MATT:
let trapTile = canvas.tiles.get('<tile-id>');
let token = _token;
await eskie.traps.fire.play(trapTile, [token]);
await eskie.traps.pitfall.play(trapTile, [token]);
await eskie.traps.projectile.play(trapTile, [token]);
await eskie.traps.spike.play(trapTile, [token]);A directional fire cone that erupts from an origin tile toward a target tile.
Tile setup: 3 tiles — Trigger → Origin → Target
| Config | Default | Description |
|---|---|---|
size |
3.5 |
Width of the fire cone in grid units |
await eskie.traps.fire.play(originTile, [token], { size: 4 });
await eskie.traps.fire.setup({ size: 4 });A hidden pit that reveals itself and causes a token to visually fall in.
Tile setup: 2 tiles — Trigger → Animation
| Config | Default | Description |
|---|---|---|
reveal |
true |
Whether to unhide the pit tile when triggered |
smokeSize |
2 |
Multiplier for the dust cloud puff size |
fallenScale |
0.3 |
Scale of the fallen token sprite shown at the pit bottom |
await eskie.traps.pitfall.play(trapTile, [token]);
await eskie.traps.pitfall.stop(trapTile); // Fades the pit tile back to hiddenA ranged trap that fires a projectile from a launcher tile toward tokens on a target tile. Supports three projectile types.
Tile setup: 3 tiles — Trigger → Launcher → Target
| Config | Default | Description |
|---|---|---|
projectileType |
(prompted) | 'arrow', 'dart', or 'javelin' |
repeats |
10 |
Number of times the projectile fires |
repeatDelay |
50 |
Milliseconds between each repeat |
splashScale |
1.5 |
Scale of the hit/splash effect |
| Type | Description |
|---|---|
arrow |
Repeating arrow volley with slight spread |
dart |
Poison dart; applies a green tint and bubble markers to hit tokens |
javelin |
Single javelin throw with a blood splash on impact |
// Setup — prompts for projectile type
await eskie.traps.projectile.setup();
// Setup with a pre-specified type
await eskie.traps.projectile.setup({ projectileType: 'dart' });
// Manual play
await eskie.traps.projectile.play(originTile, [token], {
projectileType: 'arrow',
repeats: 5,
});Spikes that shoot up from the floor under every token on the trap tile.
Tile setup: 2 tiles — Trigger → Animation
| Config | Default | Description |
|---|---|---|
delay |
500 |
Milliseconds between the spike visual and the hit effect |
await eskie.traps.spike.play(trapTile, [token], { delay: 300 });
await eskie.traps.spike.setup();When setup() completes, EMP writes MATT configuration flags to your tiles. The trigger tile receives a runcode action that fires automatically on token entry:
const playPath = tile.getFlag('eskie-macros', 'trap.playPath');
const originTileIds = tile.getFlag('eskie-macros', 'trap.trapOriginTileIds') || [];
if (playPath && typeof token !== 'undefined') {
const trap = foundry.utils.getProperty(globalThis, playPath);
if (trap && typeof trap.play === 'function') {
originTileIds.forEach(id => {
const originTile = canvas.tiles.get(id);
if (originTile) trap.play(originTile, [token]);
});
}
}The trap/origin tiles store trap.trapTargetTileIds (for 3-tile traps) and any extra configuration such as projectileType.