Summer 2026 Music Kit Competition is now here! - Create a summer themed electronic music kit and submit it by - Enter Now!

Scripting
JavaScript Basics

This page teaches you just enough JavaScript to script a map. It assumes you know Hammer, but have never written code. If you already know JavaScript, skip ahead to the Scripting Cookbook.

Every example below works inside a real script file, so feel free to paste them in and experiment. Remember that every script starts with the import line:

import { Instance } from "lambda_script/point_script";

Comments

Anything after // on a line is a comment: a note to yourself that the game ignores. Use them generously.

// This line does nothing. The next line prints a message.
Instance.Msg("Hello!"); // Comments can also follow code.

Variables

A variable is a named box that holds a value. Think of it like a math_counter, except it can hold text, numbers, lists, or anything else.

let pressCount = 0;          // A number the script can change later.
const doorName = "vault_door"; // A value that never changes.
  • Use let when the value will change (counters, flags, timers).
  • Use const when it never will (names, settings). If you're unsure, start with const; the editor will tell you if you try to change it.

Change a variable with =, and do maths with the usual symbols:

pressCount = pressCount + 1; // Add one...
pressCount++;                // ...or the short version of the same thing.

Values: text, numbers, and booleans

const mapAuthor = "ZeRo";   // Text, called a "string". Always in quotes.
const maxRounds = 12;       // A number.
const isUnlocked = false;   // A boolean: true or false. Like a logic_branch.

To build text out of other values, use a template string: backticks (`) instead of quotes, with ${...} around anything you want inserted:

Instance.Msg(`The door has been opened ${pressCount} times`);

Functions

A function is a reusable block of code with a name, the scripting equivalent of a logic_relay. Define it once, then "fire" (call) it whenever you like:

const openVault = () => {
	Instance.Msg("Opening the vault");
	Instance.EntFireAtName({ name: "vault_door", input: "Open" });
};

openVault(); // Runs the two lines above.

Functions can take inputs of their own, called parameters:

const announce = (message) => {
	Instance.Msg(`[Announcement] ${message}`);
};

announce("Round starting soon");

The (...) => { ... } style is called an arrow function. It's the style used throughout these docs.

Callbacks: the most important idea

In Hammer, you don't open a door by standing in the trigger yourself. You tell the trigger "when someone touches you, open the door". Scripting works the same way: you hand the game a function and say "run this when X happens". That handed-over function is called a callback.

Instance.OnScriptInput("StartEvent", (value) => {
	Instance.Msg("The map fired StartEvent at me!");
});

Instance.OnPlayerChat(({ player, text }) => {
	Instance.Msg(`${player.GetPlayerName()} said: ${text}`);
});

Nothing inside the callback runs when the script loads. It runs later, each time the event actually happens. Almost everything in map scripting is registering callbacks like these.

Objects

An object groups related values together under one name, using { key: value } pairs, very much like an entity's keyvalues:

const settings = {
	doorName: "vault_door",
	openDelay: 2,
	message: "The vault is opening!",
};

Instance.Msg(settings.message); // Read a value with a dot.

Many scripting functions take an object as their options, which keeps them readable:

Instance.EntFireAtName({
	name: "vault_door",
	input: "Open",
	delay: 2,
});

Arrays and loops

An array is an ordered list of values, written with square brackets. Use a for...of loop to do something with each entry:

const players = Instance.GetAllPlayerControllers();

for (const player of players) {
	Instance.Msg(`${player.GetPlayerName()} is on the server`);
}

Making decisions with if

if runs code only when a condition is true, the scripting version of a logic_branch or filter:

if (pressCount >= 3) {
	Instance.Msg("The button has been pressed enough times!");
} else {
	Instance.Msg(`Only ${pressCount} presses so far`);
}

Useful comparisons:

Written as Means
=== is equal to
!== is not equal to
> and < greater than / less than
>= and <= at least / at most
&& and (both must be true)
|| or (either can be true)

One = sets, three === compares

Writing if (count = 3) sets count to 3 instead of checking it. Always use === when comparing.

When something isn't there: undefined

When a scripting function looks for something that doesn't exist (say, an entity name with a typo), it returns the special value undefined rather than causing an error. Always check before using the result:

const door = Instance.FindEntityByName("vault_door");

if (door !== undefined) {
	Instance.Msg(door.GetClassName());
}

There is a handy shortcut: ?. (optional chaining) means "only continue if this exists":

door?.Glow({ r: 255, g: 180, b: 0 }); // Does nothing if door is undefined.

When something goes wrong: errors

If your script does something invalid, it throws an error: the current callback stops and the error is printed to the server console with the line number. That console output is your first stop when debugging. You can also catch errors yourself so the rest of your code keeps running:

try {
	const entity = Instance.FindEntityByName("temporary_target");
	entity?.Remove();
} catch (error) {
	Instance.Msg(`Could not remove entity: ${error}`);
}

Common beginner mistakes

  • Capitalisation matters everywhere. Instance.msg(...) is an error; it's Instance.Msg(...). Script input names are case-sensitive too: OpenDoor and opendoor are different inputs.
  • Forgetting the import line. Every script needs import { Instance } from "lambda_script/point_script"; at the top.
  • Missing quotes, brackets, or braces. Every ( needs a ), every { needs a }, every opening quote needs a closing one. A good editor highlights these instantly; see editor setup.
  • Reaching for setTimeout. It doesn't exist here. Use Instance.SimpleTimer, or a delay on EntFireAtName. Both are shown in the Cookbook.
  • Expecting variables to survive a reload. Reloading the script (or the map) resets all variables. To keep values, see save data in the Cookbook.

Where to next?

You now know enough to read every example in these docs. Head to the Scripting Cookbook and start building. Copying a working recipe and tweaking it is the fastest way to learn.