Character Vault
Any Concept / Any System
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools

Script:Dynamic Lighting Animation

From Roll20 Wiki

Revision as of 05:06, 3 September 2013 by Brian (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

The following script creates the API commands !snapshot, !reset, !run, and!stop.



!snapshot frames
Parameter Values
frames The number of frames to display the snapshot. The animation runs at 20fps, so using a value of 20 equates to a 1s snapshot.


You need to enter the user ID of each GM in the game into the gmIDs variable (line 5). You can find someone's user ID from their wiki user page (there is a link to your personal user page in the sidebar of this wiki) or the URL of their profile page on the rest of the site.

If you do not accurately enter the GM's user IDs, the script will ignore your commands.

Using the commands

Only the GMs can use these API commands.

In order to "record" the animation, move the player bookmark to the page with the DL layer you want to animate. Set up the paths on the DL layer as you want, and then use the !snapshot command.

The animation record will persist between game sessions, although the script is not set up to record different animations for different pages.

Once you're ready to show off your fantastical magical labyrinth to your players, use the !run command. Stop the animation with !stop.

You cannot record additional snapshots while the animation is running. If you need to change the animation or you're ready to record a different one, you need to use !reset to clear the old animation.


var animation = animation || {};

// Set to a list of the user IDs for each GM -- only the GM should be able to stop/start the animation!
// You can find your user ID by checking your userpage on the wiki, or the URL of your profile.
animation.gmIDs = [235259];

animation.running = false;

on('chat:message', function(msg) {
    if(msg.type != 'api') return;
    // Only use commands coming from a GM
    var isGM = false;
    var player = getObj('player', msg.playerid);
    _.each(animation.gmIDs, function(n) {
        if(player.get('d20userid') == n)
            isGM = true;
    if(!isGM) return;
    var parts = msg.content.split(' ');
    var command = parts.shift().substring(1);
        case 'snapshot':
                sendChat("","/w gm You cannot add a frame while the animation is running.");
            var pageid = Campaign().get('playerpageid');
            var dlPaths = findObjs({_type: 'path', _pageid: pageid, layer: 'walls'});
            var frames = parseInt(parts[0], 10);
            var pathdata = [];
            _.each(dlPaths, function(path) {
                var obj = {
                    top: path.get('top'),
                    left: path.get('left'),
                    rotation: path.get('rotation'),
                    width: path.get('width'),
                    height: path.get('height'),
                    scaleX: path.get('scaleX'),
                    scaleY: path.get('scaleY')
            state.animation.frames.push({ data: pathdata, frames: frames });
        case 'reset':
            state.animation.curr_frame = 0;
            state.animation.frames = [];
        case 'run':
            animation.running = true;
        case 'stop':
            animation.running = false;

on('ready', function() {
    if(!state.animation) state.animation = {};
    if(!state.animation.frames) state.animation.frames = [];
    if(!state.animation.curr_frame) state.animation.curr_frame = 0;
    var frame = state.animation.curr_frame;
    var frameCount = 0;
    setInterval(function() {
        if(!animation.running) return;
        if(!state.animation.frames[frame]) return;
        if(state.animation.frames[frame].frames <= frameCount)
            frameCount -= state.animation.frames[frame].frames;
            if(frame == state.animation.frames.length) frame = 0;
            state.animation.curr_frame = frame;
    }, 50);

 * Set the paths on the DL layer to the settings for the current animation frame.
animation.setupFrame = function(pathdata) {
    _.each(pathdata, function(obj) {
        var path = getObj('path',;log(obj);
            left: obj.left,
            rotation: obj.rotation,
            width: obj.width,
            height: obj.height,
            scaleX: obj.scaleX,
            scaleY: obj.scaleY


This script does not create or delete paths. If you want a frame with one or more paths missing, you can simply move them off the map.