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.

Counters are one of G.js’s most powerful abstractions. They wrap Geometry Dash’s item system — a set of integer variables that the game engine tracks at runtime — and give you a JavaScript-friendly API for reading, writing, and reacting to those values. Every arithmetic operation, comparison, and loop you perform with a counter compiles down to GD’s item triggers, so the logic runs entirely inside the game with no external JavaScript needed at play-time.

Creating a Counter

Use the counter() function to allocate a new in-game item variable:
const score = counter(0);           // starts at 0
const lives = counter(3);           // starts at 3
const flag  = counter(true);        // boolean (1 or 0)
const saved = counter(0, false, true); // persistent between attempts
num
number | boolean
default:"0"
Initial value of the counter. Booleans are converted to 1 or 0.
use_id
boolean
default:"false"
When true, treats num as an existing item ID to reuse rather than allocating a fresh one.
persistent
boolean
default:"false"
When true, the counter retains its value across attempts (deaths and restarts).
is_timer
boolean
default:"false"
When true, the counter behaves as a GD timer rather than a plain item.
bits
number
Specifies the bit-width of the counter. Useful for memory-efficient item storage.

Arithmetic Methods

Every Counter exposes chainable methods that emit the appropriate item-edit triggers when called inside a trigger function context.
MethodDescription
add(amount)Adds amount to the counter.
subtract(amount)Subtracts amount from the counter.
multiply(amount)Multiplies the counter by amount.
divide(amount)Divides the counter by amount.
set(amount)Sets the counter to an exact value.
amount can be a plain number or another Counter, letting you compose item-edit chains.
const hp = counter(100);

trigger_function(() => {
  hp.subtract(10);   // take 10 damage
  hp.multiply(2);    // double current HP
  hp.set(100);       // reset to full
});

Additional Arithmetic

MethodDescription
abs()Replaces the counter value with its absolute value.
neg()Negates the counter value.
mod(b)Computes counter mod b (number or Counter).
reset()Resets the counter to zero.

Copying and Cloning

MethodDescription
add_to(item)Adds this counter’s value into item.
copy_to(item)Copies (overwrites) this counter’s value into item.
clone()Returns a new counter that is a copy of this one.
subtract_from(b)Subtracts this counter from counter b.

Display and Object Conversion

score.display(15, 45); // creates an item-display object at (15, 45)

const obj = score.to_obj(); // returns a GJsObject you can chain .with() on
obj.with(obj_props.X, 30).add();
display(x, y)
void
Places a GD item-display object at the given coordinates. The display updates in real-time as the counter changes.
to_obj()
GJsObject
Returns the underlying GJsObject so you can attach additional properties with .with() and then .add() it.

Conditional Branching with if_is

if_is fires a trigger function whenever the counter satisfies a comparison against a constant:
const lives = counter(3);

lives.if_is(EQUAL_TO, 0, trigger_function(() => {
  // game over logic here
}));
comparison
number
One of the three comparison constants: EQUAL_TO (0), LARGER_THAN (1), or SMALLER_THAN (2).
other
number
The constant to compare against.
trig_func
TriggerFunctionGroup
The trigger function to call when the condition is true.

Comparison Constants

ConstantValueMeaning
EQUAL_TO0Counter equals other
LARGER_THAN1Counter is greater than other
SMALLER_THAN2Counter is less than other

SPWN-style Constant Ranges with to_const

to_const maps a range of possible counter values to JavaScript-time code, letting you generate different trigger logic for each value:
const level_id = counter(1);

level_id.to_const(range(1, 4), (val) => {
  // this runs at script time for each value 1, 2, 3, 4
  // val is the concrete number for that branch
  group(val).call();
});
to_const executes your callback at build time for each value in the range. It does not run arbitrary JS at play-time; it pre-generates a trigger branch for every possible value.

Floating-Point Counters

For fractional values, use float_counter:
const speed_multiplier = float_counter(1.5);
FloatCounter extends Counter with three additional rounding methods:
MethodDescription
round()Rounds the value to the nearest integer.
floor()Floors the value to the largest integer ≤ value.
ceil()Ceils the value to the smallest integer ≥ value.
float_counter accepts the same val, use_id, and persistent parameters as counter() but does not expose the is_timer or bits options.

Timers

The timer() function creates a special counter that counts time in seconds rather than arbitrary units:
const t = timer(0, 30, on_finish); // counts from 0 to 30s, calls on_finish when done
start_seconds
number
The value (in seconds) at which the timer starts.
end_seconds
number
default:"0"
The value at which the timer stops (if stop is true).
target_id
$group
default:"group(0)"
Group to call when the timer reaches end_seconds.
backwards
boolean
default:"false"
When true, the timer counts down instead of up.
seconds_only
boolean
default:"false"
When true, only whole seconds are counted.
stop
boolean
default:"true"
When true, the timer halts at end_seconds.
time_mod
number
default:"1"
Multiplier applied to the timer’s tick rate. Cannot be used together with backwards.
ignore_timewarp
boolean
default:"false"
When true, the timer is immune to timewarp triggers.
no_override
boolean
default:"false"
When true, another timer trigger cannot override this timer.
The returned Counter also exposes start(), stop(), set_start(x), and set_end(x) for controlling the timer at runtime.

While Loops

G.js supports runtime while-loops using condition helpers and the while_loop function from the control-flow module.

Condition Helpers

These functions build a condition descriptor that while_loop understands:
less_than(count, other)     // count < other
equal_to(count, other)      // count === other
greater_than(count, other)  // count > other
Each returns an object { count, comparison, other }.

while_loop(r, triggerFunction, del?)

Keeps spawning triggerFunction as long as the condition r holds:
const i = counter(0);

while_loop(less_than(i, 10), trigger_function(() => {
  i.add(1);
  // loop body here
}));
r
object
A condition object returned by less_than, equal_to, or greater_than.
triggerFunction
TriggerFunctionGroup
The trigger function to repeat while the condition is true.
del
number
Optional delay (seconds) between loop iterations.

Item Compare with compare

For comparing two counters against each other (rather than a counter against a constant), use compare:
compare(score, GREATER, high_score, new_record_fn, no_record_fn);
c1
Counter
First counter to compare.
op
number
Comparison operator. Use constants from constants.d.ts: EQ (0), GREATER (1), GREATER_OR_EQ (2), LESS (3), LESS_OR_EQ (4), NOT_EQ (5).
c2
Counter
Second counter to compare.
truei
TriggerFunctionGroup
Group to call if the comparison is true.
falsei
TriggerFunctionGroup
Group to call if the comparison is false.

Full Examples

Basic Counter Arithmetic

import '@g-js-api/g.js';

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

const score = counter(0);
const multiplier = counter(2);

// on touch: add 10 * multiplier to score
on(touch(), trigger_function(() => {
  const bonus = multiplier.clone();
  bonus.multiply(10);
  score.add_to(bonus); // score += multiplier * 10 (conceptually)
  bonus.reset();
}));

// show the score in-level
score.display(15, 45);

While Loop Countdown

import '@g-js-api/g.js';

await $.exportConfig({ type: 'savefile' });

const countdown = counter(10);

while_loop(greater_than(countdown, 0), trigger_function(() => {
  countdown.subtract(1);
}));

if_is Branching

import '@g-js-api/g.js';

await $.exportConfig({ type: 'savefile' });

const hp = counter(5);

const game_over = trigger_function(() => {
  // show game-over UI, stop level, etc.
});

hp.if_is(EQUAL_TO, 0, game_over);

to_const Range Dispatch

import '@g-js-api/g.js';

await $.exportConfig({ type: 'savefile' });

const phase = counter(1);

// At build time, generates branches for phase = 1, 2, 3
phase.to_const(range(1, 3), (val) => {
  group(val * 10).call(); // calls group 10, 20, or 30 at runtime
});

Control Flow

Learn while_loop, for_loop, and frame_loop for repeating trigger sequences.

Events

Combine counters with event triggers for reactive level logic.

Items API

Low-level item_edit and item_comp trigger wrappers.

Constants

Full list of comparison and operator constants.

Build docs developers (and LLMs) love