Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/g-js-api/G.js/llms.txt

Use this file to discover all available pages before exploring further.

One of the most powerful concepts in G.js — and in Geometry Dash level programming in general — is the trigger function: a self-contained group of GD triggers that can be spawned on demand, delayed, looped, or remapped. Understanding trigger functions and the context system they rely on is the key to writing reusable, composable level logic.

What Is a Trigger Function?

In GD, a “trigger function” is a group ID whose spawn trigger chain encodes a sequence of effects. Calling the group fires the entire sequence. G.js automates the bookkeeping — assigning IDs, chaining spawn triggers, tracking delays — so you can write sequential logic as ordinary JavaScript code.
const my_fn = trigger_function(() => {
  group(1).move(30, 0, 0.5);   // move group 1 right
  wait(0.5);                    // wait for the move to finish
  group(1).move(-30, 0, 0.5);  // move group 1 back
});

// Fire the sequence
my_fn.call();
Everything inside the callback is recorded as GD triggers placed on an auto-assigned group. The returned value is a TriggerFunctionGroup.

trigger_function(cb) and TriggerFunctionGroup

declare const trigger_function: (cb: (group: any) => void) => TriggerFunctionGroup;

interface TriggerFunctionGroup {
  value: number;       // raw group ID
  type: string;        // type tag
  call(delay?: number): void;          // spawn the trigger function (with optional delay in seconds)
  remap(...args: any[]): TriggerFunctionGroup; // remap IDs inside the function
  stop(): void;        // stop all triggers running in this function
}
MemberDescription
valueThe underlying GD group ID.
call(delay?)Emits a Spawn trigger that fires the function. Pass a number to add a spawn delay in seconds.
remap(...args)Creates a remapped variant of the trigger function with different group IDs substituted.
stop()Emits a Stop trigger targeting this function’s group.

wait(time) — Sequencing Inside Trigger Functions

wait(time) pauses the trigger sequence for time seconds by inserting spawn delay bookkeeping. It can only be called inside a trigger function callback.
trigger_function(() => {
  color(BG).set(rgb(255, 0, 0), 0);  // instant red
  wait(1);                             // wait 1 second
  color(BG).set(rgb(0, 0, 0), 0);    // instant black
});
wait() changes the active context (the group ID that newly emitted triggers will be assigned to). This is intentional and fundamental to how spawn-delay chaining works — but it means you must be careful about which group you reference after a wait().

Contexts and Why They Matter

G.js assigns triggers to contexts — named containers that correspond to GD group IDs. When a trigger function runs, each wait() or move trigger that takes time causes G.js to advance to a new context so that subsequent triggers get the correct spawn delay. This means that after a wait(), the “current group” is no longer the original group of the trigger function. If you try to call the trigger function’s own group to loop it, you need to capture the original group before any context changes occur.

$.trigger_fn_context() — Capturing the Original Group

declare const trigger_fn_context: () => $group;
Call $.trigger_fn_context() at the very start of a trigger function — before any wait() or timed operations — to store a reference to the trigger function’s original group. You can then call that group later to loop back to the beginning.
const moveloop = trigger_function(() => {
  // ✅ Capture original context before any waits
  const my_context = $.trigger_fn_context();

  group(1).move(30, 0, 0.5);
  wait(0.5);
  group(1).move(-30, 0, 0.5);
  wait(0.5);

  // ✅ Call the original context — not moveloop.call() — to loop
  my_context.call();
});

moveloop.call(); // start the loop
Do not call moveloop.call() inside the loop body itself. After the first wait(), the context has changed and you are no longer in the same group as moveloop.value. Use $.trigger_fn_context() instead.

ignore_context_change(fn) — Side Effects Without Context Drift

Sometimes you want to trigger a side effect — a flash, a sound, a camera shake — in the middle of a sequence without letting it affect the context used by the surrounding triggers. ignore_context_change runs a function while freezing the current context:
declare const ignore_context_change: (fn: Function) => void;
const moveloop = trigger_function(() => {
  const my_context = $.trigger_fn_context();

  group(1).move(30, 0, 0.5);
  wait(0.5);

  // Flash BG white — does NOT advance the context
  ignore_context_change(() => {
    color(BG).set(rgb(255, 255, 255), 0.1);
  });

  group(1).move(-30, 0, 0.5);
  wait(0.5);

  my_context.call();
});
Without ignore_context_change, the color trigger inside the callback would be placed on the current context and could interfere with spawn-delay calculations.

Full Moveloop Example (from the README)

Here is the complete example from the G.js README demonstrating all of the above concepts together:
import '@g-js-api/g.js';

await $.exportConfig({ type: 'savefile', options: { info: true } });

let my_text = unknown_g();

'Hello, World!'
  .to_obj()
  .with(obj_props.X, 45)
  .with(obj_props.Y, 45)
  .with(obj_props.GROUPS, my_text)
  .add();

let moveloop = trigger_function(() => {
  // Capture the original group BEFORE any context-changing operations
  let my_context = $.trigger_fn_context();

  my_text.move(30, 0, 0.5);   // move text right over 0.5s
  my_text.move(-30, 0, 0.5);  // move text back over 0.5s

  // Flash background WITHOUT changing the context
  ignore_context_change(() => log.runtime.flash());

  // Loop by calling the captured original context
  my_context.call();
});

moveloop.call(); // kick off the infinite loop

extend_trigger_func(t, cb) — Extending Existing Functions

You can append additional triggers to a trigger function after it has been created using extend_trigger_func. The callback receives the original context group.
declare const extend_trigger_func: (t: TriggerFunctionGroup, cb: (group: any) => void) => void;
const my_fn = trigger_function(() => {
  group(1).move(10, 0, 0.3);
});

// Add more triggers to the same function later
extend_trigger_func(my_fn, () => {
  wait(0.3);
  group(1).alpha(0, 0.2);
});
This is also accessible as $.extend_trigger_func(t, cb).

blocking_trigger_fn(func) — Blocking Execution

A blocking trigger function is a special trigger function that prevents other triggers from running until it has finished. It is useful for operations that must complete fully before the level can proceed.
declare const blocking_trigger_fn: (
  func: (stop_exec: () => void) => void
) => TriggerFunctionGroup;
The callback receives a stop_exec function. Call stop_exec() at the point where blocking should end — this allows you to unblock early rather than waiting for the entire function to complete.
const guarded = blocking_trigger_fn((stop_exec) => {
  color(BG).set(rgb(255, 0, 0), 0);
  wait(1);
  color(BG).set(rgb(0, 0, 0), 0);

  stop_exec(); // other triggers can run again from here

  // Any triggers below this line still run, but no longer block
  wait(1);
  group(99).toggle_off();
});

guarded.call();

The Context Class

G.js exposes the Context class for advanced use cases where you need to inspect or manually switch the active context.
class Context {
  name: string;
  group: $group;
  objects: Dictionary[];
  children: string[];
  linked_to?: string;

  constructor(name: string, setToDefault?: boolean, group?: $group);

  static current: string;                          // name of the active context
  static last_contexts: Record<string, string>;    // history of context transitions
  static list: Record<string, Context>;            // all registered contexts

  static set(name: string | { value: number }): void;
  static add(context: Context): void;
  static addObject(objectToAdd: any): void;
  static link(context: string, ctxLink?: string): void;
  static isLinked(ctx: Context): boolean;
  static findByGroup(groupToSearch: number | $group): Context;
  static findByName(name: string): Context;
}
MemberDescription
Context.currentThe name of the context that triggers are currently being added to.
Context.set(name)Switches the active context by name or group value.
Context.findByGroup(g)Returns the Context object that owns the given group.
Context.link(ctx, parent)Marks ctx as a child of parent, used to track trigger function hierarchies.
For most levels you will never need to interact with Context directly. $.trigger_fn_context() and ignore_context_change() cover the common cases.

Quick Reference

FunctionPurpose
trigger_function(cb)Create a callable group of triggers
wait(time)Advance the context by time seconds
$.trigger_fn_context()Get the original group of the current trigger function
ignore_context_change(fn)Run side-effect triggers without changing context
extend_trigger_func(t, cb)Append triggers to an existing trigger function
blocking_trigger_fn(func)Create a trigger function that blocks until stop_exec() is called

Export Modes

Configure how G.js exports your level to Geometry Dash.

Control Flow Guide

Loops, conditions, and sequencing patterns built on trigger functions.

Build docs developers (and LLMs) love