Roll20's API is pretty much entirely event driven. In the case of WildDice, the only event it listens to is the "chat:message" event (though it does do it's setup when the "ready" event occurs at API Sandbox startup) -- Line 169 registers the handleInput() function to be called for the "chat:message" event using the on() function. "chat:message" occurs whenever someone issues a message in the chat, be it an API command, emote, text message, roll command, whatever. The argument to a "chat:message" handler will be an object that represents the message. It has some standard properties, like "type", that you can examine to change the behavior of your script. Usually API scripts that listen to chat events only want to do something with messages with a type of 'api', which corresponds to lines in chat that began with ! such as "!wwd" and "!wd" for WildDice. The handleInput() function starts on line 84, here's a tour of what the lines do: 85-93 :: declare and initialize some variables (it used to be more important to do it at the top with "var" like I did here -- as of Javascript ES6, using "let" and "const" is the prefered way, and they don't need to be at the top of a function scope as they are block scoped (var is function scoped and hoisted, so declaring it deeper in the function would still hoist the definition to the beginning of the function scope). 95-97 :: check if this is an api message and early out if it isn't. Javascript has == and === equality operators, and corresponding != and !== inequality operators. You should always use === and !== until you learn what == and != really do (and then you'll realize you should never use them. =D). 99 :: get the display name of the issuing player, or "API" as the name if there wasn't an issuing player getObj() retrieves a Roll20 object given an object type ( 'player' here) and an object id ( msg.playerid here). You might use this function to get a graphic object, or character object or the like. There are also findObjs(), filterObjs(), allObjs() etc, which return collections of objects based on various criteria. || is the OR operation in Javascript. Unlike many other languages, the OR in Javascript doesn't return a boolean, it returns the first "truthy" value being used in the comparisons . In a practical sense, you can think of that as the first thing that's defined. So if foo, bar, and baz are 0, false, and undefined respectively, and qux is 42, this would set result to 42: let result = foo || bar || baz || qux; If getObj() returns undefined (the general "nothing to see here" value in Javascript), the result of the || will instead be the {get:()=>'API'} object. {} in Javascript defines and Object. You can think of an object very much like a Hash or Associative Array from other languages. To the left of a : is a property of the object (get in this case), and to the right is it's value ( ()=>'API' here). The => is called a Fat Arrow Function. This one defines a function that takes no arguments () and returns a string 'API'. Fat Arrow functions are new as of Javascript ES6 and are (mostly) just shorthand for something like function(){ return 'API'; }. The practical upshot of this is that the ( getObj(...) || {get: ...} ) construct will return an object guaranteed to have a property named get which is a function. That way, the .get('_displayname') will be valid to call on the result. Roll20 objects use a few functions on the object to interact with their contents. .get() and .set() are the two most common and do exactly as you imagine. '_displayname' is the property on a player object that contains a player's current name. In the case where there is no issuing player (say, the chat message was created by another API script), it will fail to find the player object and will fall back on the second half of the OR, the function that returns 'API'. In Javascript, passing more arguments to a function than it wants is not an error, so ()=>'API' will silently ignore the '_displayname' parameter and will just return 'API', initializing the who variable. This will be used later to target messages for whispered output. 101 :: Split the API command message into an array. msg.content contains what was typed (with some special substitutions to deal with inline rolls and such) into the chat. All strings in Javascript have a .split() function that returns an array based on separating the string on the parameter to .split(). /\s+/ is a regular expression that matches 1 or more whitespace characters, so this will break the command into all the words. 102 :: Switch based on the left most word of the command. If it's one of the cases of either '!wwd' or '!wd' the WildDice script will do something, otherwise execution will fall harmlessly out of the bottom of the function. 103-104 :: Matching the string '!wwd' and then setting w to true. w is initialized to false on line 86, so this is the only way it gets set to true. w is used to determine if the output should be whispered. Normally, you would have a break statement at the end of a case so that only the internals of that case get executed. Here, since "!wwd" should be identical to "!wd" except for setting the whisper flag, I let it fall through and execute the "!wd" case. 106 :: Match the "!wd" case to do the work of the function. 107-110 :: if there are no inline rolls (WildDice expects to be called like "!wd [[5d6]]" ), or if they called "!wd --help", then show the user the help message by calling the showHelp() function and passing it the who we determined on line 99. 112 :: _.pluck is a function from underscore.js (<a href="http://underscorejs.org" rel="nofollow">http://underscorejs.org</a>) which takes an array of objects and the name of a property and returns an array that contains the value of that property on each of the objects. Here I'm using that OR construct again to make sure the argument to _.pluck is an array. Arrays in Javascript are represented by [ ]. In this case, it's pulling the "v" property off of each of the inline dice roll results from the message. 113 :: Another OR construct ( this is very idiomatic in Javascript) to set pips to the outcome of the subtraction (_.reduce() is another underscore.js function, best to just go read about it if you're not familiar with the reduce operation (this is basically summing rDice)) || 0. I confess I have no idea what this is actually doing mathematically, you'd need to look at the inline rolls structure and figure it out (it looks like it would always be 0, but that's clearly not the case). 114 :: set the wildDie to the rightmost die by calling .pop() on the array of dice results. All Javascript arrays have a .push() and .pop() to treat the array like a stack by modifying the tail end (highest indexes), they also have .shift() and .unshift() that you can use to manipulate the head of the array. 115-132 :: These deal with the specific mechanics of WildDice's wild die. I'll gloss over this for round one. =D 133 :: using _.reduce() again to sum a list of dice. In this case, the rolled dice (without the wild die) along with any bonus dice (from the wild die being a 6 on line 127), plus the wild die, plus whatever pips represents. 135-162 :: creating a big block of HTML to send back to the chat with the sendChat() function. You see w being used with the ternary operator. The ternary operator is basically an inline If-Then-Else. ( Check ? True : False ). So if w is true, the message will start with '/w gm ', otherwise it will start with '/direct '. The rest of this block is mostly string concatenation to form the output. + is used for concatenating strings (which means if you have variables with numbers as strings you might get some confusing output if you don't parseInt() on them first). _.map() is another function from Underscore.js. Basically it returns an array that contains the result of calling the function in the second parameter on each of the values in the collection that is the first parameter. Map and Reduce are important concepts in modern programming that you can read about all over the internets. That pretty well sums up the handleInput() function. There are two useful helper functions on lines: 70-75 :: getDiceCounts(), when given an array of numbers will return an object with the numbers as the properties and the number of times it occurs as the value of each. So, this would tell you how many 6s were rolled, or how many 3s, etc. 77-82 :: getDiceArray() takes an object with numbers as the properties and counts as the values and returns an array with the numbers repeated as many times as their count. Effectively, these two convert between each other (though note that order is not preserved ( getDiceArray(getDiceCounts( [1,3,1,6,2] )) would probably return [1,1,2,3,6] ). Other functions: 12-32 :: The ch() function is a helper I use to output the HTML Entities for characters that would be problematic both in the source code and in the output text. I mainly use it in the showHelp() function to output things like < and > without them creating HTML. Since the API management is web based, using an HTML entity directly ( like &gt; ) would be expanded in the code when it gets pasted in the browser, leading to the problem yet again, which is why the & is assembled separately on line 29. 34-36 :: checkInstall() is a function in most of my scripts that just sets things up in the state object and does other startup tasks, as well as outputting the current version number to the API log. The log output is all it does here. 38-65 :: showHelp() whispers a help message to the player name passed to it on line 108. It basically explains using WildDice and consists of a bunch string concatenation to make an HTML message. 168-170 :: registerEventHandlers() is another function I use in many of my scripts. Usually, it's only registering a chat handler, but sometimes it registers other things (like 'change:graphic' handlers ). 179-184 :: an anonymous function passed directly to the on() function to register an event handler for the "ready" action. The "ready" action is fired once when the API Sandbox starts up, right after it has loaded all the objects in memory. Doing things before the "ready" event can cause weird results (like getting an "add:graphic" event call for every graphic object in the game), so it's usually a good idea to delay doing anything until the "ready" event has fired. 'use strict' is a special string that causes the Javascript interpreter to hold your code to a higher standard. Probably not needed in post ES6 days. 182 :: call the CheckInstall() function (an alias for checkInstall created on line 173, see below) 183 :: call the RegisterEventHandlers() function (an alias for registerEventHandlers created on line 174, see below) Most of my scripts use a construct called the Revealing Module Pattern. Rather than describe it again, you can read about it here: <a href="https://wiki.roll20.net/API:Cookbook#Revealing_Mod" rel="nofollow">https://wiki.roll20.net/API:Cookbook#Revealing_Mod</a>... or on the wider internet. Basically, line 6 creates an object called WildDice which is the result of calling an anonymous function (an IIFE -- Immediately Invoked Function Expression) which defines a bunch of functionality (which is held privately inside the function and then exposed via the aliasing object returned at the end (line 172-175). This works because of a concept called a Closure... see the wider internet... =D Hope that helps with the initial round of investigation. I'm happy to talk at length about anything javascript or API related (or pretty much anything. =D ), just ask. Also, there's lots of great detail in the API section of the wiki: <a href="https://wiki.roll20.net/API:Introduction" rel="nofollow">https://wiki.roll20.net/API:Introduction</a>