Skip to content

sendMessage()

Write a message to the chat log, as the acting token.

Part of the Action API · Function reference

Signature

sendMessage(message: string): void

Synchronous, returns nothing.

Parameters

Parameter Type Description
message string The message. HTML is allowed. Dice expressions inside it are rolled — see below.

Returns

Nothing.

What happens to your string

Three passes run over every message, in this order.

1. Dice expressions are rolled. Any NdS pattern — an explicit count, then one of d4, d6, d8, d10, d12, d20, d100, with an optional +n or -n — is rolled and replaced with a rich dice row.

sendMessage('The trap fires for 2d6 damage!');   // rolls 2d6 for real

Text inside double quotes is skipped, which is the escape hatch when you want the literal characters:

sendMessage('The spell deals "2d6" fire damage.'); // shows 2d6, rolls nothing

d6 without a count is not matched, and neither are non-standard die sizes like 2d7.

2. Plain text is wrapped. If the string contains no <, it is wrapped in a <div> so it lays out like every other chat line. A string that already contains a tag is left alone.

3. The message is tagged. An invisible marker identifying this action run is prefixed to the message. The chat log groups every message from one run into a single bordered entry, so a chatty action stays one item in the log.

Examples

A line of narration

sendMessage(`${token.name} steps back into the shadows.`);

Formatted output

sendMessage(`
  <b>${token.name}</b> casts <i>Bless</i>
  <ul>
    <li>${targets.map((t) => t.name).join('</li><li>')}</li>
  </ul>
`);

A number you already rolled

const damage = roll('2d6', false);
sendMessage(`Searing pain: <b>${damage}</b>.`);

Conditional output

if (!target) {
  sendMessage('<i>No target selected.</i>');
  return;
}

Notes and gotchas

  • Double-rolling is the classic mistake. Interpolating a rolled number into the string is fine; leaving the expression in the string is not — sendMessage('Damage: 2d6') rolls a second, unrelated 2d6 inside chat. If you want one roll with a sentence around it, use roll(expr, { text }).
  • Returning a string does the same thing. An action whose last statement is return 'text' sends that string to chat with the same processing, so a one-line action needs no sendMessage() at all. Returning anything else that is not undefined/null prints an orange warning instead.
  • HTML is rendered, not sanitized here. Keep interpolated values under your own control; a token name is fine, a pasted block of untrusted markup is not.
  • In the Test panel nothing is sent. Messages are captured and listed in the panel instead, which is what makes it safe to iterate.
  • Damage cards emitted by applyDamage() travel through this same function and are passed through untouched.

See also