Перейти к содержимому

Hudifine

Создавай собственные HUD-оверлеи с помощью простого скриптового языка. Знаний в кодинге модов не требуется.

Fabric
Загрузчики
Fabric
Скачиваний на Modrinth
797
Подписчиков на Modrinth
4
версий
5
Обновлён
19 июня 202619 июн.
Опубликован
в 2026
Это библиотека — она нужна другим модам и сама ничего не добавляет в игру
The HUDs Displayed — This picture has HUDs displayed to represent how they can look like. · свайп

Коротко о моде

Библиотека — нужна другим модам
Работает на Fabric
Для Minecraft 26.1.2–26.2
Ставится только в игру; на сервер ставить не нужно
Последняя версия — 2.0.1 от 19 июня 2026
Лицензия GPL-3.0-or-later — бесплатно
Где нужен
В игреобязателенНа серверене нужен

Ставится только в игру; на сервер ставить не нужно

Версии игры26.1.2–26.2
Описание переведено автоматическиПоказать оригинал (EN)

Hudifine — это HUD-мод, который позволяет любому легко создавать HUD-ы с помощью HUD Script, отображающего выбранные вами метрики.

Откройте чат, чтобы добавить и настроить их.

Ниже приведена документация по HUDScript — скриптовому языку Hudifine.

Документация HUDScript

Документация для разработчиков HUD Script

HUD Script — это безопасный, изолированный формат скриптов для создания полностью настраиваемых игровых HUD-ов в Minecraft (Fabric). Скрипты вставляются и запускаются; среда разработки модов не требуется.


Содержание

  1. Обзор
  2. Структура скрипта
  3. Бюджет экрана (правило 30%)
  4. Источники данных

    • Игрок
    • Мир
    • Производительность
    • Бой
    • Инвентарь
    • Ввод
    • Окружение
    • Состояние игры
    • Мультиплеер
    • Время
  5. Система компоновки

    • Порядок и слои
  6. Стилизация
  7. Элементы
  8. Условия и логика
  9. События
  10. Переключатели доступности
  11. API настроек игрока
  12. Анимации
  13. Руководство по реализации CPS
  14. Полные примеры

Обзор

HUD Script — это декларативный + событийно-ориентированный формат скриптов. Скрипты определяют:

  • Какие данные отображать (из фиксированного набора разрешённых источников данных)
  • Как их отображать (полная визуальная свобода в рамках бюджета экрана)
  • Настройки, задаваемые игроком (доступность, переключатели, цвета и т. д.)

Скрипты изолированы по своей природе. Они могут только:

  • ✅ Читать из разрешённых источников данных
  • ✅ Отрисовывать в HUD-оверлей
  • ✅ Визуально реагировать на ввод игрока
  • ❌ Делать сетевые запросы
  • ❌ Обращаться к файловой системе
  • ❌ Взаимодействовать с чем-либо за пределами виджета

Структура скрипта

Каждый скрипт имеет три необязательных блока верхнего уровня:

meta {
  name: "My Widget"
  author: "yourname"
  version: "1.0.0"
  description: "A short description of what this widget does."
}

settings {
  // Player-configurable options exposed in the right-click menu
}

widget {
  // Layout, elements, styling, logic
}

Обязателен только блок widget.


Бюджет экрана (правило 30%)

Виджет может занимать не более 30% площади экрана игрока в любой момент времени.

  • Площадь экрана вычисляется как screenWidth × screenHeight
  • Ограничивающий прямоугольник вашего виджета (все элементы вместе) не должен превышать screenWidth × screenHeight × 0.30
  • Это проверяется во время выполнения; если ваш виджет превышает 30%, он будет автоматически уменьшен, а в редакторе виджетов появится предупреждение
  • Виджеты, которые отключены или полностью прозрачны, не учитываются в бюджете
  • Несколько виджетов имеют каждый свой независимый бюджет в 30%

Совет: Разумно используйте свойство size и тестируйте на разных разрешениях. Проектируйте исходя из 1920×1080.


Источники данных

Все источники данных доступны только для чтения. Вызывайте их внутри значений элементов с помощью get().

Игрок

ИсточникВозвращаетОписание
player.healthfloatТекущее здоровье (0.0-20.0)
player.maxHealthfloatМаксимальное здоровье, включая поглощение
player.absorptionfloatСердца поглощения
player.hungerintУровень еды (0-20)
player.saturationfloatУровень насыщения (0.0-20.0)
player.exhaustionfloatЗначение истощения (0.0-4.0)
player.airintТики запаса воздуха (0-300)
player.xpintВсего очков опыта
player.xpLevelintТекущий уровень опыта
player.xpProgressfloatПрогресс опыта до следующего уровня (0.0-1.0)
player.speedfloatТекущая скорость передвижения (блоков/сек)
player.isSprintingboolБежит ли игрок
player.isSneakingboolКрадётся ли игрок
player.isSwimmingboolПлывёт ли игрок
player.isFlyingboolЛетит ли игрок (креатив/элитра)
player.isFallingboolПадает ли игрок
player.isOnGroundboolСтоит ли игрок на земле
player.isInWaterboolНаходится ли игрок в воде
player.isInLavaboolНаходится ли игрок в лаве
player.fallDistancefloatТекущая высота падения в блоках
player.reachDistancefloatТекущая дальность досягаемости
player.namestringИмя игрока
player.uuidstringUUID игрока
player.gamemodestringsurvival, creative, adventure, spectator
player.scoreintТекущий счёт игрока в таблице очков
player.pingintЗадержка в мс (только в мультиплеере)

World

ИсточникВозвращаетОписание
world.xfloatКоордината X игрока
world.yfloatКоордината Y игрока
world.zfloatКоордината Z игрока
world.blockXintКоордината X блока игрока (округлённая вниз)
world.blockYintКоордината Y блока игрока (округлённая вниз)
world.blockZintКоордината Z блока игрока (округлённая вниз)
world.chunkXintКоордината X текущего чанка
world.chunkZintКоордината Z текущего чанка
world.facingstringСторона света: N, NE, E, SE, S, SW, W, NW
world.facingDegreesfloatПоворот в градусах (0-360)
world.pitchfloatНаклон камеры (-90 до 90)
world.yawfloatПоворот камеры (0-360)
world.dimensionstringoverworld, nether, end или пользовательское пространство имён
world.biomestringНазвание текущего биома (например, minecraft:plains)
world.lightLevelintУровень освещения от блоков у ног игрока (0-15)
world.skyLightLevelintУровень небесного освещения в позиции игрока (0-15)
world.moonPhaseintФаза луны (0-7)
world.isRainingboolИдёт ли дождь
world.isThunderingboolИдёт ли гроза
world.rainStrengthfloatИнтенсивность дождя (0.0-1.0)
world.difficultystringpeaceful, easy, normal, hard
world.namestringНазвание мира/сервера
world.seedstringСид мира (только в одиночной игре, на серверах возвращает "hidden")
world.spawnXintКоордината X точки появления мира
world.spawnZintКоордината Z точки появления мира
world.distanceToSpawnfloatРасстояние до точки появления мира в блоках

Performance

ИсточникВозвращаетОписание
perf.fpsintТекущее количество кадров в секунду
perf.fpsAvgfloatСредний FPS за последние 5 секунд
perf.fpsMinintМинимальный FPS за последние 5 секунд
perf.fpsMaxintМаксимальный FPS за последние 5 секунд
perf.frameTimefloatВремя последнего кадра в миллисекундах
perf.frameTimeAvgfloatСреднее время кадра за последние 5 секунд
perf.tpsfloatТиков в секунду на сервере (только в мультиплеере)
perf.msptfloatМиллисекунд на тик (сервер, только в мультиплеере)
perf.chunkUpdatesintОбновлений чанков за этот кадр
perf.renderedChunksintКоличество отрисованных чанков
perf.entitiesintСущностей в дальности прорисовки
perf.blockEntitiesintБлочных сущностей в дальности прорисовки
perf.particlesintАктивных частиц

Combat

ИсточникВозвращаетОписание
combat.attackCooldownfloatПрогресс перезарядки атаки (0.0-1.0)
combat.attackCooldownMsintМиллисекунд до полной перезарядки атаки
combat.isAttackingboolАтакует ли игрок прямо сейчас
combat.lastDamagefloatПоследний полученный урон
combat.lastDamageSourcestringИсточник последнего урона (например, fire, fall, player)
combat.killCountintУбийств игроком за эту сессию
combat.deathCountintСмертей игрока за эту сессию
combat.kdrfloatСоотношение убийств/смертей за эту сессию
combat.targetNamestringИмя сущности, на которую смотрит игрок (если есть)
combat.targetHealthfloatЗдоровье сущности, на которую смотрит игрок
combat.targetMaxHealthfloatМаксимальное здоровье сущности, на которую смотрит игрок
combat.targetDistancefloatРасстояние до целевой сущности
combat.targetTypestringТип сущности, на которую смотрит игрок
combat.isInCombatboolПолучал ли игрок урон или наносил ли его недавно
combat.combatTimerintСекунд с последнего боевого действия

Инвентарь

ИсточникВозвращаетОписание
inventory.hotbarSlotintТекущий слот хотбара (0-8)
inventory.mainHandItemstringID предмета в основной руке
inventory.mainHandCountintКоличество предметов в стаке в основной руке
inventory.mainHandDurabilityintПрочность предмета в основной руке
inventory.mainHandMaxDurabilityintМаксимальная прочность предмета в основной руке
inventory.mainHandDurabilityPctfloatПрочность предмета в основной руке в % (0.0-1.0)
inventory.offHandItemstringID предмета во второй руке
inventory.offHandCountintКоличество предметов в стаке во второй руке
inventory.offHandDurabilityintПрочность предмета во второй руке
inventory.helmetItemstringID шлема
inventory.helmetDurabilityintПрочность шлема
inventory.helmetDurabilityPctfloatПрочность шлема в % (0.0-1.0)
inventory.chestplateItemstringID нагрудника
inventory.chestplateDurabilityintПрочность нагрудника
inventory.chestplateDurabilityPctfloatПрочность нагрудника в % (0.0-1.0)
inventory.leggingsItemstringID поножей
inventory.legginsDurabilityintПрочность поножей
inventory.leggingsDurabilityPctfloatПрочность поножей в % (0.0-1.0)
inventory.bootsItemstringID ботинок
inventory.bootsDurabilityintПрочность ботинок
inventory.bootsDurabilityPctfloatПрочность ботинок в % (0.0-1.0)
inventory.arrowCountintКоличество стрел в инвентаре
inventory.totalSlotsintВсего слотов в инвентаре (36)
inventory.usedSlotsintКоличество занятых слотов в инвентаре
inventory.emptySlotsintКоличество пустых слотов в инвентаре
inventory.xpBottleCountintПузырьки опыта в инвентаре

Ввод

Источники ввода отражают то, что игрок физически нажимает. Они только для отображения; вы не можете перехватывать, блокировать или перенаправлять ввод.

ИсточникВозвращаетОписание
input.forwardboolКлавиша W зажата
input.backwardboolКлавиша S зажата
input.leftboolКлавиша A зажата
input.rightboolКлавиша D зажата
input.jumpboolПробел зажат
input.sneakboolShift зажат
input.sprintboolКлавиша спринта зажата
input.attackboolЛевая кнопка мыши зажата
input.useboolПравая кнопка мыши зажата
input.dropboolКлавиша Q зажата
input.inventoryboolКлавиша инвентаря зажата
input.swapboolКлавиша F (смена рук) зажата
input.hotbar1-input.hotbar9boolКлавиши слотов хотбара зажаты
input.cpsintCPS левой кнопки (кликов в секунду)
input.rcpsintCPS правой кнопки
input.mouseXintПозиция мыши по X на экране
input.mouseYintПозиция мыши по Y на экране
input.mouseDeltaXfloatСмещение мыши по X за этот кадр
input.mouseDeltaYfloatСмещение мыши по Y за этот кадр
input.sensitivityfloatТекущая чувствительность мыши (0.0-1.0)

Окружение

ИсточникВозвращаетОписание
env.timeOfDayintТики мира (0-24000)
env.timeStringstringФорматированное время (например, 6:00 AM)
env.dayCountintПрошло игровых дней
env.temperaturefloatТемпература биома на позиции игрока
env.humidityfloatВлажность биома на позиции игрока
env.canSeeSkyboolВидит ли игрок небо
env.isUndergroundboolНаходится ли игрок под землёй (нет доступа к небу)
env.nearestVillageDistancefloatРасстояние до ближайшей обнаруженной деревни (в блоках)
env.isInVillageboolНаходится ли игрок внутри деревни
env.nearestPlayerDistancefloatРасстояние до ближайшего другого игрока (мультиплеер)
env.nearestPlayerNamestringИмя ближайшего другого игрока

Состояние игры

ИсточникВозвращаетОписание
game.isPausedboolПриостановлена ли игра
game.isInGuiboolОткрыт ли какой-либо GUI
game.isInventoryOpenboolОткрыт ли инвентарь
game.isInBedboolСпит ли игрок
game.isRidingboolЕдет ли игрок на сущности
game.ridingEntityTypestringТип сущности, на которой едет игрок
game.ridingEntityHealthfloatЗдоровье сущности, на которой едет игрок
game.isElytraFlyingboolЛетит ли игрок на элитрах
game.elytraHealthintТекущая прочность элитр
game.elytraSpeedfloatТекущая скорость полёта на элитрах (блоков/сек)
game.potionEffects`list`ID активных эффектов зелий
game.potionEffectAmplifiersmap<string, int>Уровень каждого активного эффекта
game.potionEffectDurationsmap<string, int>Длительность в тиках каждого активного эффекта
game.scoreboardObjectivestringНазвание текущей цели таблицы очков в сайдбаре
game.scoreboardScoreintОчки игрока по текущей цели в сайдбаре
game.bossBarNamestringНазвание активного боссбара (если есть)
game.bossBarProgressfloatПрогресс боссбара (0.0-1.0)
game.isSpectatingEntityboolНаблюдает ли игрок за сущностью
game.spectatingEntityTypestringТип сущности, за которой наблюдает игрок

Мультиплеер

ИсточникВозвращаетОписание
server.namestringНазвание сервера / IP
server.motdstringMOTD сервера
server.playerCountintТекущее количество игроков онлайн
server.maxPlayersintМаксимальное количество игроков на сервере
server.pingintПинг до сервера в мс
server.tpsfloatTPS сервера
server.isLANboolПодключён ли игрок к LAN-серверу
server.isSingleplayerboolИграет ли игрок в одиночной игре
server.versionstringВерсия Minecraft на сервере

Время

ИсточникВозвращаетОписание
clock.hourintРеальный час (0-23)
clock.minuteintРеальная минута (0-59)
clock.secondintРеальная секунда (0-59)
clock.timeStringstringФорматированное реальное время (например, 14:32)
clock.timeString12string12-часовой формат (например, 2:32 PM)
clock.sessionTimeintСекунды в текущей игровой сессии
clock.sessionTimeStringstringФорматированное время сессии (например, 1h 23m)
clock.datestringРеальная дата (например, 2025-04-26)
clock.unixTimestampintUnix-время (секунды)

Система компоновки

Виджеты используют простую блочную компоновку с привязкой к позициям на экране.

Точки привязки

widget {
  anchor: top-left       // top-left, top-center, top-right
                         // middle-left, center, middle-right
                         // bottom-left, bottom-center, bottom-right
  offsetX: 10            // Смещение в пикселях от точки привязки по X (может быть отрицательным)
  offsetY: 10            // Смещение в пикселях от точки привязки по Y (может быть отрицательным)
}

Размеры

widget {
  width: 120             // Фиксированная ширина в пикселях
  height: auto           // "auto" подстраивается под содержимое, либо фиксированные пиксели
  padding: 8             // Одинаковый отступ (или padding: 8 4 для вертикального/горизонтального)
  margin: 4              // Внешний отступ
}

Направление

widget {
  direction: column      // "column" (вертикальный стек) или "row" (горизонтальный стек)
  gap: 4                 // Промежуток между дочерними элементами в пикселях
  align: start           // "start", "center", "end" - выравнивание по поперечной оси
  justify: start         // "start", "center", "end", "space-between" - выравнивание по главной оси
}

### Z-Index

```hud
widget {
  zIndex: 10             // Чем выше значение, тем поверх остальных виджетов рендерится
}

Порядок и слои

По умолчанию элементы рендерятся в том порядке, в котором они написаны в скрипте, сверху вниз. Это можно переопределить свойством order у любого элемента или группы.

widget {
  direction: column

  text { value: "I appear second" order: 2 color: #ffffff fontSize: 12 }
  text { value: "I appear first"  order: 1 color: #aaaaaa fontSize: 10 }
  text { value: "I appear third"  order: 3 color: #555555 fontSize: 9 }
}

order работает как CSS order: меньшие числа рендерятся первыми (выше или левее — зависит от direction). Элементы без order по умолчанию имеют order: 0 и рендерятся раньше явно упорядоченных.

order также можно использовать внутри group:

group {
  direction: row

  text { value: "CPS" order: 2 color: #aaaaaa fontSize: 9 }
  keyIndicator { key: input.attack label: "LMB" order: 1 size: 20 borderRadius: 8 activeColor: #ffffff inactiveColor: #ffffff33 }
}

Совет: используй order, когда хочешь сгруппировать логику скрипта, но при этом изменить визуальное расположение. Если у всего есть явный order, чище просто переписать скрипт в нужном порядке.


Стилизация

Фон

widget {
  background: #00000088        // Hex-цвет с необязательной альфой (последние 2 цифры)
  background: transparent      // Без фона
  borderRadius: 6              // Скругление углов в пикселях
  border: 1 #ffffff44          // Рамка: ширина цвет
  backdropBlur: 4              // Размытие пикселей позади виджета (зависит от GPU)
}

Стилизация текста

text {
  value: get(player.health)
  color: #ffffff
  fontSize: 12               // В пикселях (рекомендуется 8-32)
  fontWeight: bold           // "normal", "bold"
  fontStyle: normal          // "normal", "italic"
  shadow: true               // Тень текста в стиле Minecraft
  shadowColor: #00000066
  letterSpacing: 0           // Пиксели между символами
  lineHeight: 1.2            // Множитель высоты строки
  align: left                // "left", "center", "right"
  truncate: 20               // Максимум символов до обрезки (опционально)
  uppercase: false           // Принудительный верхний регистр
}

Цвета

Цвета — это hex-строки: #RRGGBB или #RRGGBBAA (с альфой).

color: #ff0000             // Красный, полностью непрозрачный
color: #ff000088           // Красный, 50% прозрачности
color: #fff                // Сокращённая запись (разворачивается в #ffffff)

Прозрачность

widget {
  opacity: 0.8             // От 0.0 (невидимый) до 1.0 (полностью непрозрачный)
}

Элементы

Элементы — это визуальные строительные блоки внутри блока widget.

text

Отображает строковое значение.

text {
  value: "FPS: {get(perf.fps)}"    // Встроенные выражения с {}
  color: #ffffff
  fontSize: 12
  shadow: true
}

bar

Полоса заполнения (здоровье, опыт, перезарядка и т. д.)

bar {
  value: get(player.health)
  max: get(player.maxHealth)
  width: 100
  height: 8
  fillColor: #ff4444
  backgroundColor: #00000066
  borderRadius: 4
  direction: left-to-right    // "left-to-right", "right-to-left", "bottom-to-top", "top-to-bottom"
}

icon

Отрисовывает иконку предмета или блока Minecraft.

icon {
  item: get(inventory.mainHandItem)    // Строка ID предмета
  size: 16                             // Размер иконки в пикселях
}

circle

Круговой индикатор прогресса.

circle {
  value: get(combat.attackCooldown)    // 0.0-1.0
  radius: 12
  strokeWidth: 3
  color: #ffffff
  backgroundColor: #ffffff33
  startAngle: -90                      // Градусы — 0 = справа, -90 = сверху
  direction: clockwise                 // "clockwise" или "counterclockwise"
}

### `image`

Отображает статичную текстуру из ресурспака.

```hud
image {
  texture: "hud:textures/my_icon.png"    // Namespace:path within resource pack
  width: 16
  height: 16
  tint: #ffffff                          // Optional color tint
}

keyIndicator

Показывает визуальную клавишу, которая подсвечивается при нажатии.

keyIndicator {
  key: input.forward
  label: "W"
  activeColor: #ffffff
  inactiveColor: #ffffff44
  size: 20              // Width and height of the key in pixels
  width: 20             // Override width only (useful for SPACE, LMB, RMB)
  borderRadius: 8       // Higher = more rounded. Use 999 for a full pill shape
  fontSize: 9           // Label font size inside the key
  shadow: true          // Text shadow on label
}

Совет: Для широких клавиш вроде SPACE, LMB и RMB ставь width больше size, чтобы растянуть их по горизонтали, сохранив ту же высоту. borderRadius от 8 до 12 соответствует виду Lunar Client.

group

Контейнер для группировки и вложения элементов друг в друга.

group {
  direction: row
  gap: 4
  background: #00000066
  padding: 6
  borderRadius: 4

  text { value: "Health: " color: #aaaaaa fontSize: 11 }
  text { value: "{get(player.health)}" color: #ff4444 fontSize: 11 }
}

separator

Горизонтальная или вертикальная разделительная линия.

separator {
  direction: horizontal    // "horizontal" or "vertical"
  color: #ffffff22
  thickness: 1
  length: 80               // Pixels, or "auto" to fill available space
  margin: 4
}

spacer

Пустое пространство между элементами.

spacer {
  size: 8
}

Условия и логика

if / else

Показывают или скрывают элементы в зависимости от условий.

if get(player.health) < 6 {
  text {
    value: "⚠ LOW HEALTH"
    color: #ff0000
    fontSize: 14
    shadow: true
  }
} else if get(player.health) < 10 {
  text {
    value: "Health is getting low"
    color: #ffaa00
    fontSize: 12
  }
} else {
  // nothing
}

Встроенные выражения

Используй {} внутри строковых значений для встроенных выражений:

text { value: "You are in the {get(world.dimension)}" }
text { value: "XP Level: {get(player.xpLevel)} ({round(get(player.xpProgress) * 100)}%)" }

Математические функции

ФункцияОписание
round(x)Округление до ближайшего целого
floor(x)Округление вниз
ceil(x)Округление вверх
abs(x)Модуль числа
min(x, y)Минимум из двух значений
max(x, y)Максимум из двух значений
clamp(x, min, max)Ограничение значения между min и max
lerp(a, b, t)Линейная интерполяция
pct(value, max)Возвращает (value / max) * 100
format(x, decimals)Форматирует число до N знаков после запятой

Строковые функции

ФункцияОписание
upper(s)Верхний регистр строки
lower(s)Нижний регистр строки
concat(a, b)Объединяет две строки
trim(s, n)Обрезает строку до N символов
replace(s, from, to)Заменяет подстроку

Операторы сравнения

==, !=, <, >, <=, >=, &&, ||, !

if get(world.dimension) == "nether" && get(player.health) < 10 {
  text { value: "Danger!" color: #ff0000 }
}

События

Реагируй на события, чтобы визуально обновлять виджет.

on keypress(input.attack) {
  // Triggered once when key is first pressed
  text {
    value: "Attacking!"
    color: #ff4444
    fadeOut: 500    // Fade out after 500ms
  }
}

on keyhold(input.sneak) {
  // Triggered every tick while key is held
}

on keyrelease(input.jump) {
  // Triggered once when key is released
}

on event(player.health < 5) {
  // Triggered when condition becomes true
  // Re-triggers if condition goes false then true again
}

on tick {
  // Runs every game tick (20 times/sec)
}

on frame {
  // Runs every render frame
}

---

## Переключатели доступности

Разработчики могут добавлять переключатели и настройки для игроков с особыми потребностями доступности. Они отображаются в панели настроек по правому клику на виджете.

```hud
settings {
  toggle "High Contrast Mode" {
    id: highContrast
    default: false
    description: "Increases color contrast for better visibility."
  }

  toggle "Reduce Motion" {
    id: reduceMotion
    default: false
    description: "Disables animations and transitions."
  }

  toggle "Large Text" {
    id: largeText
    default: false
    description: "Increases all text sizes by 1.5×."
  }

  toggle "Colorblind Mode" {
    id: colorblindMode
    default: false
    description: "Replaces color-coded indicators with shapes/patterns."
  }

  toggle "Screen Reader Hints" {
    id: screenReaderHints
    default: false
    description: "Shows additional text labels on icon-only elements."
  }
}

Затем используйте значения настроек в своём виджете:

widget {
  text {
    value: "HP: {get(player.health)}"
    color: if setting(highContrast) then #ffff00 else #ffffff
    fontSize: if setting(largeText) then 18 else 12
    shadow: true
  }
}

API настроек игрока

Помимо переключателей доступности, вы можете добавлять полностью настраиваемые игроком параметры.

Типы настроек

settings {

  // Выбор цвета
  color "Health Bar Color" {
    id: healthColor
    default: #ff4444
    description: "Color of the health bar fill."
  }

  // Слайдер (числовой диапазон)
  slider "Widget Opacity" {
    id: widgetOpacity
    min: 0.1
    max: 1.0
    step: 0.05
    default: 0.85
    description: "Transparency of the widget background."
  }

  // Выпадающий список
  select "Display Mode" {
    id: displayMode
    options: ["compact", "normal", "expanded"]
    default: "normal"
    description: "How much information to show."
  }

  // Текстовое поле (только отображение метки)
  text "Custom Label" {
    id: customLabel
    default: "My Widget"
    maxLength: 20
    description: "Custom title displayed at the top."
  }

  // Переключатель (булево значение)
  toggle "Show Widget" {
    id: showWidget
    default: true
    description: "Toggle the entire widget on or off."
  }

  // Привязка клавиши (только отображение ввода — показывает, какая клавиша нажата)
  keybind "Highlight Key" {
    id: highlightKey
    default: input.forward
    description: "Which key to highlight in the keystroke display."
  }

}

Использование настроек в виджете

widget {
  opacity: setting(widgetOpacity)
  visible: setting(showWidget)

  text {
    value: setting(customLabel)
    fontSize: 11
    color: #aaaaaa
  }

  bar {
    value: get(player.health)
    max: get(player.maxHealth)
    fillColor: setting(healthColor)
    width: 100
    height: 8
  }
}

Анимации

Анимации автоматически отключаются, когда у игрока включён reduceMotion (если вы определили этот переключатель). Всегда проверяйте это перед использованием анимаций в виджетах, учитывающих доступность.

text {
  value: "⚠ LOW HEALTH"
  color: #ff0000

  animate {
    property: opacity
    from: 1.0
    to: 0.3
    duration: 600         // Миллисекунды
    easing: ease-in-out   // "linear", "ease-in", "ease-out", "ease-in-out"
    loop: true
    pingpong: true        // Реверс на каждом цикле
    paused: setting(reduceMotion)
  }
}

Переход (при смене состояния)

text {
  value: "{get(perf.fps)}"
  color: #ffffff

  transition {
    property: color
    duration: 200
    easing: ease-out
  }
}

Руководство по реализации CPS

Этот раздел предназначен для разработчиков модов Hudifine, реализующих источники данных input.cps и input.rcps на стороне Java.

CPS (клики в секунду) — это значение, которое Minecraft сам по себе не отслеживает. Тебе нужно реализовать счётчик кликов, используя скользящее временное окно.

Как это работает

Отслеживай каждый левый клик (атака) и правый клик (использование) с временной меткой. Чтобы получить текущий CPS, посчитай, сколько кликов произошло за последние 1000 мс.

Рекомендуемая реализация на Java (Fabric + Mixin)

Шаг 1 — Храни временные метки кликов

// In your HudifineDataProvider or equivalent class
private static final List<Long> leftClickTimes = new ArrayList<>();
private static final List<Long> rightClickTimes = new ArrayList<>();

public static void registerLeftClick() {
    long now = System.currentTimeMillis();
    leftClickTimes.add(now);
    // Prune old entries older than 1 second
    leftClickTimes.removeIf(t -> now - t > 1000);
}

public static void registerRightClick() {
    long now = System.currentTimeMillis();
    rightClickTimes.add(now);
    rightClickTimes.removeIf(t -> now - t > 1000);
}

public static int getLeftCPS() {
    long now = System.currentTimeMillis();
    leftClickTimes.removeIf(t -> now - t > 1000);
    return leftClickTimes.size();
}

public static int getRightCPS() {
    long now = System.currentTimeMillis();
    rightClickTimes.removeIf(t -> now - t > 1000);
    return rightClickTimes.size();
}

Шаг 2 — Подключись к кликам мыши через Mixin

@Mixin(MinecraftClient.class)
public class MouseClickMixin {

    @Inject(method = "doAttack", at = @At("HEAD"))
    private void onLeftClick(CallbackInfo ci) {
        HudifineDataProvider.registerLeftClick();
    }

    @Inject(method = "doItemUse", at = @At("HEAD"))
    private void onRightClick(CallbackInfo ci) {
        HudifineDataProvider.registerRightClick();
    }
}

Шаг 3 — Выведи данные в движок скриптов

Сопоставь input.cps → HudifineDataProvider.getLeftCPS() и input.rcps → HudifineDataProvider.getRightCPS() в своём резолвере источников данных.

Примечания

  • Скользящее окно в 1000 мс — это стандарт, используемый Lunar Client, Badlion и большинством PvP-клиентов
  • doAttack срабатывает при каждой попытке взмаха, включая промахи. Это соответствует тому, как Lunar считает CPS
  • doItemUse срабатывает при правом клике независимо от того, какой предмет в руке, что тоже соответствует ожидаемому поведению
  • Оба списка очищаются при чтении, поэтому они остаются небольшими даже во время длительных сессий

Полные примеры

Минимальный счётчик FPS

meta {
  name: "FPS Counter"
  author: "example"
  version: "1.0.0"
}

widget {
  anchor: top-right
  offsetX: -10
  offsetY: 10
  background: #00000066
  padding: 6
  borderRadius: 4

  text {
    value: "{get(perf.fps)} FPS"
    color: #ffffff
    fontSize: 12
    shadow: true
  }
}

Отображение нажатий клавиш

meta {
  name: "Keystrokes"
  author: "example"
  version: "1.0.0"
}

settings {
  color "Active Key Color" { id: activeColor default: #ffffff }
  color "Inactive Key Color" { id: inactiveColor default: #ffffff33 }
  toggle "Show CPS" { id: showCps default: true }
}

widget {
  anchor: bottom-right
  offsetX: -10
  offsetY: -10
  direction: column
  gap: 3

  group {
    direction: row
    justify: center
    gap: 3

    keyIndicator { key: input.forward label: "W" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 borderRadius: 8 }
  }

  group {
    direction: row
    gap: 3

    keyIndicator { key: input.left label: "A" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 borderRadius: 8 }
    keyIndicator { key: input.backward label: "S" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 borderRadius: 8 }
    keyIndicator { key: input.right label: "D" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 borderRadius: 8 }
  }

  group {
    direction: row
    justify: center

    keyIndicator { key: input.jump label: "SPACE" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 width: 66 borderRadius: 8 }
  }

  group {
    direction: row
    gap: 3

    keyIndicator { key: input.attack label: "LMB" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 width: 40 borderRadius: 8 }
    keyIndicator { key: input.use label: "RMB" activeColor: setting(activeColor) inactiveColor: setting(inactiveColor) size: 20 width: 40 borderRadius: 8 }
  }

  if setting(showCps) {
    group {
      direction: row
      gap: 6
      justify: center

      text { value: "{get(input.cps)} CPS" color: #aaaaaa fontSize: 10 }
      text { value: "{get(input.rcps)} CPS" color: #aaaaaa fontSize: 10 }
    }
  }
}

---

### Full Status HUD

```hud
meta {
  name: "Status HUD"
  author: "example"
  version: "1.0.0"
  description: "Здоровье, голод, броня, опыт и координаты."
}

settings {
  toggle "Показывать координаты" { id: showCoords default: true }
  toggle "Показывать броню" { id: showArmor default: true }
  toggle "Показывать опыт" { id: showXp default: true }
  toggle "Режим высокой контрастности" { id: highContrast default: false description: "Более контрастные цвета." }
  toggle "Крупный текст" { id: largeText default: false }
  color "Цвет здоровья" { id: healthColor default: #ff4444 }
  slider "Прозрачность" { id: opacity min: 0.2 max: 1.0 step: 0.05 default: 0.85 }
}

widget {
  anchor: bottom-left
  offsetX: 10
  offsetY: -60
  background: #00000066
  padding: 8
  borderRadius: 6
  opacity: setting(opacity)
  direction: column
  gap: 5

  // Health
  group {
    direction: row
    gap: 6
    align: center

    text { value: "❤" color: setting(healthColor) fontSize: if setting(largeText) then 16 else 11 }
    bar {
      value: get(player.health)
      max: get(player.maxHealth)
      width: 80
      height: if setting(largeText) then 10 else 7
      fillColor: setting(healthColor)
      backgroundColor: #ffffff22
      borderRadius: 3
    }
    text {
      value: "{floor(get(player.health))}/{floor(get(player.maxHealth))}"
      color: if setting(highContrast) then #ffff00 else #ffffff
      fontSize: if setting(largeText) then 14 else 10
    }
  }

  // Hunger
  group {
    direction: row
    gap: 6
    align: center

    text { value: "🍗" color: #ffaa44 fontSize: if setting(largeText) then 16 else 11 }
    bar {
      value: get(player.hunger)
      max: 20
      width: 80
      height: if setting(largeText) then 10 else 7
      fillColor: #ffaa44
      backgroundColor: #ffffff22
      borderRadius: 3
    }
    text {
      value: "{get(player.hunger)}/20"
      color: if setting(highContrast) then #ffff00 else #ffffff
      fontSize: if setting(largeText) then 14 else 10
    }
  }

  // XP
  if setting(showXp) {
    group {
      direction: row
      gap: 6
      align: center

      text { value: "✦" color: #55ff55 fontSize: if setting(largeText) then 16 else 11 }
      bar {
        value: get(player.xpProgress)
        max: 1.0
        width: 80
        height: if setting(largeText) then 10 else 7
        fillColor: #55ff55
        backgroundColor: #ffffff22
        borderRadius: 3
      }
      text {
        value: "Lv {get(player.xpLevel)}"
        color: if setting(highContrast) then #ffff00 else #55ff55
        fontSize: if setting(largeText) then 14 else 10
      }
    }
  }

  // Armor
  if setting(showArmor) {
    separator { direction: horizontal color: #ffffff22 thickness: 1 length: auto margin: 2 }

    group {
      direction: row
      gap: 4
      align: center

      icon { item: get(inventory.helmetItem) size: 14 }
      icon { item: get(inventory.chestplateItem) size: 14 }
      icon { item: get(inventory.leggingsItem) size: 14 }
      icon { item: get(inventory.bootsItem) size: 14 }
    }
  }

  // Coordinates
  if setting(showCoords) {
    separator { direction: horizontal color: #ffffff22 thickness: 1 length: auto margin: 2 }

    text {
      value: "X {floor(get(world.x))}  Y {floor(get(world.y))}  Z {floor(get(world.z))}"
      color: if setting(highContrast) then #ffff00 else #aaaaaa
      fontSize: if setting(largeText) then 13 else 10
    }

    text {
      value: "Facing {get(world.facing)} · {get(world.biome)}"
      color: if setting(highContrast) then #ffff00 else #777777
      fontSize: if setting(largeText) then 12 else 9
    }
  }
}

---

*Эта документация описывает HUD Script v1.0. Если у вас есть вопросы или вы хотите внести вклад, делитесь своими скриптами в сообществе.*

</details>

<details>
<summary>Руководство по интеграции модов</summary>

# Hudifine — руководство по интеграции модов

Hudifine предоставляет API поставщиков данных, которое позволяет любому моду на Fabric регистрировать собственные источники данных. После регистрации ваши данные становятся доступны внутри HUDScript через `get()` — точно так же, как встроенные источники вроде `get(perf.fps)` или `get(player.health)`.

---

## Требования

- Fabric Loader `>=0.15.0`
- Minecraft `>=26.1.2`
- Hudifine, установленный как зависимость

---

## 1. Добавьте Hudifine как зависимость

В вашем `build.gradle`:

```groovy
repositories {
    maven { url = uri("https://cdn.jsdelivr.net/gh/Pacsy1/hudifine@main/public-maven/") }
}

dependencies {
    modImplementation "dev.hudifine:hudifine-api:1.0.0"
}

В вашем fabric.mod.json объявите его как обязательную зависимость:

{
  "depends": {
    "hudifine": ">=1.0.0"
  }
}

2. Реализуйте поставщик данных

Hudifine предоставляет типизированные интерфейсы поставщиков. Выберите тот, который подходит вашим данным.

Доступные типы поставщиков

ИнтерфейсВозвращаемый типПример использования
IntDataProviderintFPS, пинг, количество сущностей
FloatDataProviderfloatTPS, скорость, температура
StringDataProviderStringНазвание биома, измерение, статус
BooleanDataProviderbooleanБежит ли игрок, на земле ли он

Пример: поставщик FPS

import dev.hudifine.api.provider.IntDataProvider;

public class FpsProvider implements IntDataProvider {

    @Override
    public String getId() {
        return "mymod.fps"; // через точку, совпадает с вызовом get() в HUDScript
    }

    @Override
    public String getDisplayName() {
        return "FPS Counter";
    }

    @Override
    public int getValue() {
        return Minecraft.getInstance().getFps();
    }
}

Соглашение об именовании ID

ID поставщиков используют точечную нотацию, чтобы совпадать с тем, как вызываются источники данных в HUDScript:

mymod.fps        → get(mymod.fps)
mymod.ping       → get(mymod.ping)
mymod.something  → get(mymod.something)

ID должны быть уникальными. Дубликаты ID отклоняются при загрузке с предупреждением в логе Hudifine.


3. Зарегистрируйте поставщика через entrypoint

В вашем fabric.mod.json зарегистрируйте класс поставщика под entrypoint hudifine:provider:

{
  "entrypoints": {
    "hudifine:provider": [
      "com.yourmod.FpsProvider"
    ]
  }
}

Несколько поставщиков сразу:

{
  "entrypoints": {
    "hudifine:provider": [
      "com.yourmod.FpsProvider",
      "com.yourmod.PingProvider",
      "com.yourmod.BiomeProvider"
    ]
  }
}

Hudifine автоматически находит и загружает всех зарегистрированных поставщиков при запуске. Никакого дополнительного кода инициализации с вашей стороны не требуется.


4. Использование ваших данных в HUDScript

После регистрации ваш поставщик доступен в любом HUDScript через get() — так же, как встроенные источники.

Базовое использование

widget {
  anchor: top-right
  offsetX: -10
  offsetY: 10
  background: #00000066
  padding: 6
  borderRadius: 4

  text {
    value: "{get(mymod.fps)} FPS"
    color: #ffffff
    fontSize: 12
    shadow: true
  }
}

С условиями

widget {
  anchor: top-right
  offsetX: -10
  offsetY: 10
  background: #00000066
  padding: 6
  borderRadius: 4

  text {
    value: "{get(mymod.fps)} FPS"
    color: if get(mymod.fps) < 30 then #ff4444 else if get(mymod.fps) < 60 then #ffaa00 else #ffffff
    fontSize: 12
    shadow: true
  }
}

С полосой

widget {
  anchor: bottom-left
  offsetX: 10
  offsetY: -10
  background: #00000066
  padding: 8
  borderRadius: 6
  direction: column
  gap: 4

  text {
    value: "My Mod Stats"
    color: #aaaaaa
    fontSize: 10
  }

  group {
    direction: row
    gap: 6
    align: center

    text { value: "FPS" color: #aaaaaa fontSize: 10 }
    bar {
      value: get(mymod.fps)
      max: 260
      width: 80
      height: 7
      fillColor: #55ff55
      backgroundColor: #ffffff22
      borderRadius: 3
    }
    text {
      value: "{get(mymod.fps)}"
      color: #ffffff
      fontSize: 10
    }
  }
}

### С настройками игрока

Данные вашего провайдера работают со всеми возможностями HUDScript, включая API настроек игрока:

```hud
settings {
  toggle "Show My Mod Stats" { id: showStats default: true }
  color "Stat Color" { id: statColor default: #55ff55 }
}

widget {
  visible: setting(showStats)

  text {
    value: "{get(mymod.fps)} FPS"
    color: setting(statColor)
    fontSize: 12
    shadow: true
  }
}

5. Необязательно: метаданные провайдера

Реализуйте HudifineProviderMeta, чтобы показывать более подробную информацию об источнике в браузере провайдеров Hudifine прямо в игре:

import dev.hudifine.api.provider.IntDataProvider;
import dev.hudifine.api.provider.HudifineProviderMeta;

public class FpsProvider implements IntDataProvider, HudifineProviderMeta {

    @Override
    public String getId() { return "mymod.fps"; }

    @Override
    public String getDisplayName() { return "FPS Counter"; }

    @Override
    public int getValue() { return Minecraft.getInstance().getFps(); }

    // Optional metadata
    @Override
    public String getDescription() {
        return "Current rendered frames per second.";
    }

    @Override
    public String getCategory() {
        return "performance"; // Groups it with perf.fps, perf.tps etc. in the browser
    }

    @Override
    public String getUnit() {
        return "fps";
    }
}

6. Рекомендации по производительности

getValue() вызывается каждый кадр. Сделайте его быстрым:

  • Кэшируйте дорогие вычисления и обновляйте их по тику, а не каждый кадр
  • Избегайте создания объектов внутри getValue(), где возможно используйте примитивы
  • Если ваши данные меняются только при определённых событиях, обновляйте поле по этому событию и возвращайте закэшированное поле

Хороший пример:

public class EntityCountProvider implements IntDataProvider {

    private int cachedCount = 0;

    @SubscribeEvent
    public void onTick(TickEvent event) {
        // Runs 20x/sec instead of every frame
        this.cachedCount = world.getEntities().size();
    }

    @Override
    public String getId() { return "mymod.entityCount"; }

    @Override
    public String getDisplayName() { return "Nearby Entity Count"; }

    @Override
    public int getValue() {
        return cachedCount; // Just a field read - instant
    }
}

7. Публикация в магазине

Вероятно, стоит включить Hudifine в название вашего мода — для этого просто начните название мода с 'Hudifine' для лучшей находимости.


8. Создание HUD с вашими данными

Это руководство охватывает только сторону интеграции мода. Чтобы узнать, как на самом деле писать виджеты HUDScript, использующие данные вашего провайдера, элементы, разметку, стилизацию, условия, анимации, настройки и многое другое, обратитесь к документации для разработчиков HUDScript выше.


Итог

ШагЧто делать
1Добавьте Hudifine API как зависимость
2Реализуйте типизированный интерфейс провайдера с ID в точечной нотации
3Зарегистрируйте его в fabric.mod.json в разделе hudifine:provider
4Пользователи получают доступ к вашим данным через get(yourid) в HUDScript
5(Необязательно) Реализуйте HudifineProviderMeta для браузера прямо в игре
6Держите getValue() быстрым — он выполняется каждый кадр
7(Необязательно) Опубликуйте мод на Modrinth, включив Hudifine в его название
8Смотрите документацию для разработчиков HUDScript, чтобы создавать настоящие виджеты

Hudifine Mod Integration Guide - v1.0

Частые вопросы

Как установить Hudifine?

Установите Fabric под свою версию Minecraft, скачайте Hudifine под ту же версию и загрузчик, положите файл в папку mods и запустите игру с профилем загрузчика.

Для каких версий Minecraft есть Hudifine?

У Hudifine есть сборки для Minecraft 26.1.2–26.2.

Нужен ли Hudifine на сервере?

Ставится только в игру; на сервер ставить не нужно

Лицензия и источник
GNU General Public License v3.0 or laterможно использовать и распространять; изменённые версии — под той же лицензией и с исходным кодом
Оригинал — Modrinth↗Файлы — без изменений, проверены по SHA-512Это ваш мод? Правообладателям

Сайт использует cookie: необходимые — для входа и темы, а также счётчики посещений Яндекс Метрика и LiveInternet — по ним мы видим, как пользуются сайтом. Рекламных cookie у нас нет. Подробнее