Skip to content

KubeJS Examples

hp-1e edited this page Oct 25, 2026 · 1 revision

English | 中文

Examples

Put server scripts in kubejs/server_scripts and client scripts in kubejs/client_scripts. Attribute IDs below use 1.20.1 / 1.21.1 names. On 26.1.2, drop the generic. prefix (e.g. minecraft:max_health).

New pool, category and skill

SkillAtlasEvents.definitions(event => {
  event.createPool('pack_farming')
    .name('Farming points')
    .acquisition('harvest', 16, 1, 0)
    .targets(['#minecraft:crops'])

  event.createCategory('pack_farming')
    .name('Farming')
    .icon('minecraft:wheat')
    .pool('pack_farming')

  event.createNode('pack_harvest_health')
    .name('Farmer Constitution')
    .description('Increases max health.')
    .category('pack_farming')
    .icon('minecraft:golden_carrot')
    .position(0, 0)
    .level(1, rank => {
      rank.cost({ type: 'skill_points', amount: 1 })
      rank.attributeReward('minecraft:generic.max_health', 2, 'add')
    })
})

Choose one of two paths

SkillAtlasEvents.definitions(event => {
  event.createNode('pack_path_blade')
    .name('Path of the Blade')
    .category('pack_farming')
    .position(-60, 80)
    .requires('pack_harvest_health')
    .choiceGroup('pack_path')
    .level(1, rank => {
      rank.cost({ type: 'skill_points', amount: 2 })
      rank.attributeReward('minecraft:generic.attack_damage', 2, 'add')
    })

  event.createNode('pack_path_shield')
    .name('Path of the Shield')
    .category('pack_farming')
    .position(60, 80)
    .requires('pack_harvest_health')
    .choiceGroup('pack_path')
    .level(1, rank => {
      rank.cost({ type: 'skill_points', amount: 2 })
      rank.attributeReward('minecraft:generic.armor', 4, 'add')
    })
})

Learning one path locks the other until the learned one is reset.

Events

SkillAtlasEvents.beforeLearn('pack_harvest_health', event => {
  if (String(event.player.level.dimension) === 'minecraft:the_nether') {
    event.deny(Text.red('Leave the Nether before learning this'))
  }
})

SkillAtlasEvents.pointsChanging('mining', event => {
  if (event.source === 'acquire' && event.delta > 0) {
    event.delta = event.delta * 2
  }
})

SkillAtlasEvents.learned(event => {
  event.player.tell(Text.gold('Skill raised to level ' + event.newLevel))
})

Custom condition, reward and cost

SkillAtlasEvents.conditionTypes(event => {
  event.register('pack:quest_gate', type => {
    type.validate(data => typeof data.flag === 'string' && typeof data.label === 'string')
      .test((ctx, data) => ctx.player.persistentData.getBoolean(data.flag))
      .describe((ctx, data) => Text.gold(data.label))
  })
})

SkillAtlasEvents.rewardTypes(event => {
  event.register('pack:apple_gift', type => {
    type.validate(data => data.count >= 1 && data.count <= 64 && data.count === Math.floor(data.count))
      .describe((ctx, data) => Text.green('Apple ×' + data.count))
      .onLearn((ctx, data) => ctx.player.give(Item.of('minecraft:apple', data.count)))
  })
})

SkillAtlasEvents.definitions(event => {
  event.modifyNode('haste', node => {
    node.condition('pack:quest_gate', { flag: 'intro_done', label: 'Finish the intro quest' })
      .level(1, rank => rank.customReward('pack:apple_gift', { count: 1 }))
  })
})

SkillAtlasEvents.learningCost('haste', event => {
  if (event.player.persistentData.getBoolean('discount')) {
    event.amount = Math.floor(event.amount * 0.8)
  }
  event.items = [{ item: 'minecraft:emerald', count: 2 }]
})

External activity

SkillAtlasEvents.acquisitionTypes(event => {
  event.register('pack:machine', type => {
    type.name('Machine processing').description('Process items in a specific machine')
      .unit('count')
      .validate(data => typeof data.machine === 'string')
      .test((ctx, data) => ctx.payload.machine === data.machine)
  })
})

SkillAtlasEvents.definitions(event => {
  event.createPool('machine').name('Processing points')
    .customAcquisition('pack:machine', { machine: 'press' }, 8, 1, 20)
  event.createCategory('industry').name('Industry').pool('machine')
})

// Inside the real server event of the mod you integrate:
// SkillAtlas.player(event.player).emitAcquisition('pack:machine', { machine: 'press' }, 1)

// In your pack's reset flow:
// SkillAtlas.player(event.player).resetAcquisition('machine')

// From a server quest reward:
// SkillAtlas.player(event.player).focus('haste')

Client tooltip and navigation

SkillAtlasClientEvents.tooltip('haste', event => {
  event.add(Text.gold('Quest hint: finish the mining intro first'))
})

// In a quest book client button:
// SkillAtlasClient.open('mining')
// SkillAtlasClient.focus('haste')

// Read the full tooltip for an external screen:
// const lines = SkillAtlasClient.tooltip('haste')

Clone this wiki locally