Scripting Introduction
Scripting Introduction
Section titled “Scripting Introduction”Journey includes a built-in scripting engine called Ceremony that lets you write server-side JavaScript to extend your server far beyond what JSON configuration alone can achieve. Powered by GraalJS, Ceremony gives you a full ES2023+ JavaScript runtime running inside your Minecraft server — with direct access to players, events, particles, combat, scheduling, HUD elements, and more.
If you have ever wanted to script a custom minigame, build a dynamic quest sequence, create an interactive puzzle, or just automate tedious admin tasks — Ceremony scripting is how you do it.
What is Ceremony Scripting?
Section titled “What is Ceremony Scripting?”Ceremony is Journey’s JavaScript scripting layer. It embeds the GraalJS engine (a high-performance JavaScript implementation from Oracle’s GraalVM project) directly into your Fabric server. This means:
- Server-side execution — Scripts run on the server, not the client. No client mods required for script logic.
- ES2023+ features — Full modern JavaScript support including
const/let, arrow functions, template literals, destructuring,async/await, Promises, optional chaining, nullish coalescing, and more. - Safe sandboxing — Scripts run inside a controlled environment with access only to the APIs Ceremony exposes. They cannot arbitrarily access the filesystem or network.
- Hot-reloadable — Edit your scripts and reload them without restarting the server.
Capabilities Overview
Section titled “Capabilities Overview”Ceremony scripts have access to a rich set of APIs:
| Capability | Description |
|---|---|
| 140+ Events | Listen for player actions, block changes, entity interactions, Pokemon events, combat, movement, chat, and more |
| Game.* Namespaces | Access particles, sounds, combat, entities, scheduling, HUD, camera, regions, display, and state through organized namespaces |
| Player Wrappers | Rich Player interface with messaging, teleportation, inventory access, effects, and metadata |
| State Management | Persistent key-value storage via State and per-player data via PlayerData |
| Java Interop | GraalJS allows calling Java/Kotlin classes directly when you need deeper access |
| Global Functions | Convenience functions for messaging, sounds, titles, delays, and broadcasting |
| Scheduling | Tick-based timers, repeating tasks, sequences, and async delays |
| HUD Elements | Boss bars, action bars, sidebars, titles, and toast notifications |
Installation
Section titled “Installation”Ceremony scripts are plain .js files placed in the scripts/ folder at the root of your server directory (next to your mods/ and config/ folders):
server/├── mods/├── config/├── scripts/│ ├── welcome.js│ ├── daily-rewards.js│ ├── gym-battle.js│ └── utils/│ └── helpers.js└── ...Any file with a .js extension inside scripts/ will be loaded automatically when the server starts or when you run a reload.
Script Lifecycle
Section titled “Script Lifecycle”Every Ceremony script follows a simple lifecycle:
// Called when the script is loaded or reloadedfunction onEnable() { console.log('My script is starting up!');
// Register event listeners Events.on('PlayerJoinEvent', (event) => { const player = wrapPlayer(event.getEntity()); msg(player, '<green>Welcome to the server!'); });}
// Called when the script is unloaded (before reload or shutdown)function onDisable() { console.log('My script is shutting down!');}| Function | When It Runs | Purpose |
|---|---|---|
onEnable() | Script load or /ceremony reload | Register event listeners, initialize state, start timers |
onDisable() | Script unload, before reload, or server shutdown | Clean up resources, save state, cancel timers |
Events.on() | Any time during onEnable() | Subscribe to specific game events |
ES Module Features
Section titled “ES Module Features”Because Ceremony uses GraalJS with ES2023+ support, you can write modern JavaScript freely:
// const and let (block-scoped variables)const MAX_PLAYERS = 10;let currentRound = 0;
// Arrow functionsconst greet = (player) => msg(player, '<green>Hello!');
// Template literalsconst announcement = `Round ${currentRound} is starting!`;
// Destructuringconst { x, y, z } = player.getPosition();
// Async/await with Promisesasync function countdown(player) { for (let i = 5; i > 0; i--) { title(player, `<gold>${i}`, '<gray>Get ready...'); await delay(20); // 20 ticks = 1 second } title(player, '<green>GO!', '');}
// Optional chaining and nullish coalescingconst teamName = player.getTeam()?.getName() ?? 'No Team';
// Spread operatorconst allPlayers = [...Game.entities.players()];
// Array methodsconst nearbyPlayers = allPlayers.filter(p => { const dist = p.distanceTo(origin); return dist < 50;});IntelliSense Setup
Section titled “IntelliSense Setup”Ceremony ships with a TypeScript declaration file that provides autocomplete, type checking, and inline documentation in editors like VS Code:
- Copy
ceremony-api.d.tsfrom the Ceremony release into atypes/folder in your scripts project. - Add a triple-slash reference at the top of each script file:
/// <reference path="types/ceremony-api.d.ts" />
function onEnable() { // Your editor now provides autocomplete for all Ceremony APIs Events.on('PlayerJoinEvent', (event) => { const player = wrapPlayer(event.getEntity()); msg(player, '<green>Welcome!'); });}Your project structure should look like:
scripts/├── types/│ └── ceremony-api.d.ts├── welcome.js└── daily-rewards.jsTypeScript Support
Section titled “TypeScript Support”Ceremony supports .ts (TypeScript) files in addition to .js. TypeScript files are transpiled automatically before execution, giving you type-safety and better IDE support.
To use TypeScript:
- Copy
globals.d.tsfrom the Ceremony release into yourscripts/directory (or atypes/subfolder). - Add a triple-slash reference at the top of your
.tsfile:
/// <reference path="./globals.d.ts" />
function onEnable() { Events.on('playerJoin', (player: any) => { msg(player, '<green>Welcome!'); });}With TypeScript, your editor will provide richer autocomplete, inline errors, and documentation. The Script Editor’s Export dialog can export directly as .ts with type annotations included.
Module System
Section titled “Module System”Ceremony supports require() for importing shared code between scripts. Modules use the CommonJS pattern:
function clamp(value, min, max) { return Math.max(min, Math.min(max, value));}
function randomBetween(min, max) { return min + Math.random() * (max - min);}
module.exports = { clamp, randomBetween };const { clamp, randomBetween } = require('./utils/math-helpers');
function onEnable() { Events.on('playerJoin', (player) => { const bonus = clamp(randomBetween(1, 100), 10, 50); msg(player, `<gold>Your bonus: ${bonus}`); });}Resolution order:
- Relative paths (
./foo,../bar) resolve from the current script’s directory - Bare names (
utils) resolve from thescripts/root .jsextension is added automatically if omitted
Reloading Scripts
Section titled “Reloading Scripts”After editing a script, reload all scripts in-game with:
/ceremony reloadThis will:
- Call
onDisable()on every currently loaded script - Unregister all event listeners
- Reload all
.jsfiles from thescripts/folder - Call
onEnable()on every script
You do not need to restart the server. Changes take effect immediately.
What You Can Build
Section titled “What You Can Build”Here are some examples of what servers have built with Ceremony scripting:
- Custom gym battles with automated matchmaking, scoring, and badge rewards
- Daily login rewards that scale with consecutive days
- Interactive puzzles using block interactions, particle trails, and timed sequences
- Spawn protection with dynamic particle borders and warning messages
- Automated tournaments with brackets, timers, and announcements
- Economy integration with custom shops, trading, and currency management
- Dynamic weather events that spawn rare Pokemon during thunderstorms
- Minigames like parkour races, scavenger hunts, and capture-the-flag
Next Steps
Section titled “Next Steps”Ready to start scripting? Here is the recommended path:
- Global Functions — Learn the built-in utility functions available everywhere
- Game Namespace — Explore the full
Game.*API for particles, combat, HUD, and more - Your First Script — Follow a hands-on tutorial to build your first working script