Your First Script
Your First Script
Section titled “Your First Script”This tutorial walks you through building a complete welcome script from scratch. By the end, you will have a script that greets players with a styled message, plays a sound, shows a title, enforces a cooldown, and spawns particles — all in under 50 lines of code.
Step 1: Create the File
Section titled “Step 1: Create the File”Create a new file called welcome.js inside the scripts/ folder at your server root:
server/├── mods/├── config/├── scripts/│ └── welcome.js└── ...If the scripts/ folder does not exist yet, create it manually. Ceremony will automatically load any .js file placed here.
Step 2: Add the Type Reference
Section titled “Step 2: Add the Type Reference”Open welcome.js in your editor and add the triple-slash reference at the very top of the file. This enables IntelliSense autocomplete if you are using VS Code or a similar editor:
/// <reference path="types/ceremony-api.d.ts" />Step 3: Add onEnable
Section titled “Step 3: Add onEnable”Every Ceremony script needs an onEnable() function. This is the entry point that runs when the script is loaded or reloaded:
/// <reference path="types/ceremony-api.d.ts" />
function onEnable() { Logger.info('Welcome script loaded!');}Save the file and run /ceremony reload in-game. You should see Welcome script loaded! in your server console. If you see an error instead, double-check for typos.
Step 4: Listen for Player Join
Section titled “Step 4: Listen for Player Join”Now add an event listener inside onEnable() that fires whenever a player joins the server. The playerJoin event provides the raw serverPlayer object — you need to wrap it with wrapPlayer() to access the convenience API:
function onEnable() { Logger.info('Welcome script loaded!');
Events.on('playerJoin', (serverPlayer) => { const player = wrapPlayer(serverPlayer); msg(serverPlayer, '<green>Welcome to the server, <bold>' + player.name + '</bold>!'); });}Step 5: Add a Sound
Section titled “Step 5: Add a Sound”Make the welcome feel polished by playing a level-up sound when the player joins. Add this line right after the msg() call:
Events.on('playerJoin', (serverPlayer) => { const player = wrapPlayer(serverPlayer); msg(serverPlayer, '<green>Welcome to the server, <bold>' + player.name + '</bold>!'); sound(serverPlayer, 'entity.player.levelup', 0.8, 1.2);});The parameters for sound() are:
| Parameter | Value | Description |
|---|---|---|
player | serverPlayer | Who hears the sound |
soundName | 'entity.player.levelup' | The Minecraft sound ID |
volume | 0.8 | Volume (0.0 to 1.0+) |
pitch | 1.2 | Pitch (0.5 = low, 1.0 = normal, 2.0 = high) |
Step 6: Add a Title
Section titled “Step 6: Add a Title”Show a large welcome title on the player’s screen. Titles support MiniMessage formatting for colors and styles:
Events.on('playerJoin', (serverPlayer) => { const player = wrapPlayer(serverPlayer); msg(serverPlayer, '<green>Welcome to the server, <bold>' + player.name + '</bold>!'); sound(serverPlayer, 'entity.player.levelup', 0.8, 1.2); title(serverPlayer, '<gold>Welcome!', '<gray>' + player.name, 10, 60, 20);});The title() parameters are:
| Parameter | Value | Description |
|---|---|---|
player | serverPlayer | Who sees the title |
main | '<gold>Welcome!' | Large text in the center of the screen |
sub | '<gray>' + player.name | Smaller subtitle below the main text |
fadeIn | 10 | Ticks to fade in (10 ticks = 0.5 seconds) |
stay | 60 | Ticks to display (60 ticks = 3 seconds) |
fadeOut | 20 | Ticks to fade out (20 ticks = 1 second) |
Step 7: Add a Cooldown
Section titled “Step 7: Add a Cooldown”Right now the welcome fires every single time a player joins, including disconnects and reconnects. Use the player data cooldown system to only show the welcome once per hour:
Events.on('playerJoin', (serverPlayer) => { const player = wrapPlayer(serverPlayer);
// Check if the player is still on cooldown (3600 seconds = 1 hour) if (player.data.isOnCooldown('welcome_message')) { return; // Skip the welcome, they saw it recently }
// Set the cooldown for 1 hour (3600 seconds) player.data.cooldown('welcome_message', 3600);
msg(serverPlayer, '<green>Welcome to the server, <bold>' + player.name + '</bold>!'); sound(serverPlayer, 'entity.player.levelup', 0.8, 1.2); title(serverPlayer, '<gold>Welcome!', '<gray>' + player.name, 10, 60, 20);});Step 8: Add Particles
Section titled “Step 8: Add Particles”Spawn a circle of particles at the player’s feet when they join to make the welcome visually striking:
Events.on('playerJoin', (serverPlayer) => { const player = wrapPlayer(serverPlayer);
if (player.data.isOnCooldown('welcome_message')) { return; } player.data.cooldown('welcome_message', 3600);
msg(serverPlayer, '<green>Welcome to the server, <bold>' + player.name + '</bold>!'); sound(serverPlayer, 'entity.player.levelup', 0.8, 1.2); title(serverPlayer, '<gold>Welcome!', '<gray>' + player.name, 10, 60, 20);
// Spawn a circle of happy villager particles around the player Game.particles.circle( serverPlayer.serverLevel(), // the world/level player.pos.x, // center X player.pos.y + 0.5, // center Y (slightly above feet) player.pos.z, // center Z ParticleTypes.HAPPY_VILLAGER,// particle type 2.0, // radius 20 // number of particles );});Step 9: The Complete Script
Section titled “Step 9: The Complete Script”Here is the full assembled script with all the pieces together:
/// <reference path="types/ceremony-api.d.ts" />
function onEnable() { Logger.info('Welcome script loaded!');
Events.on('playerJoin', (serverPlayer) => { // Wrap the raw player to access convenience properties const player = wrapPlayer(serverPlayer);
// Only show the welcome once per hour if (player.data.isOnCooldown('welcome_message')) { return; } player.data.cooldown('welcome_message', 3600);
// Send a colored chat message msg(serverPlayer, '<green>Welcome to the server, <bold>' + player.name + '</bold>!');
// Play a level-up sound (slightly louder than default, higher pitch) sound(serverPlayer, 'entity.player.levelup', 0.8, 1.2);
// Show a large title on screen with fade in/stay/fade out title(serverPlayer, '<gold>Welcome!', '<gray>' + player.name, 10, 60, 20);
// Spawn a particle circle at the player's feet Game.particles.circle( serverPlayer.serverLevel(), player.pos.x, player.pos.y + 0.5, player.pos.z, ParticleTypes.HAPPY_VILLAGER, 2.0, 20 ); });}
function onDisable() { Logger.info('Welcome script unloaded!');}Step 10: Test It
Section titled “Step 10: Test It”- Save the file to
scripts/welcome.js - Run
/ceremony reloadin-game or from the server console - Check the console for
Welcome script loaded! - Disconnect and rejoin the server
- You should see the chat message, hear the sound, see the title, and see particles at your feet
What You Built
Section titled “What You Built”In this tutorial you learned how to:
| Concept | API Used |
|---|---|
| Script lifecycle | onEnable(), onDisable() |
| Event listening | Events.on('playerJoin', callback) |
| Player wrapping | wrapPlayer(serverPlayer) |
| Chat messages | msg(player, miniMessage) |
| Sound effects | sound(player, name, volume, pitch) |
| Screen titles | title(player, main, sub, fadeIn, stay, fadeOut) |
| Cooldowns | player.data.cooldown(), player.data.isOnCooldown() |
| Particles | Game.particles.circle(...) |
Next Steps
Section titled “Next Steps”Now that you have a working script, explore these topics:
- Common Patterns — Reusable code patterns for guards, traversal, scheduling, and more
- Example Scripts — Full annotated scripts for treecapitator, vein miner, treasure hunting, and more
- Game Namespace — Deep dive into
Game.particles,Game.combat,Game.hud, and other namespaces