signal is a config-driven, extensible library for dispatching player feedback on the
Bukkit API. It turns a single path (companion.summon-success) into a composite burst of
feedback: chat message, actionbar, title, sound, potion effect, sent all at once or filtered
down to exactly the pieces a caller needs.
signal focuses on doing one thing well: letting a plugin say "send the player this feedback"
without hardcoding which channels that feedback travels through. The core module has no
dependency on Configurate or any config format. It's built purely against Bukkit/Paper, so you
can construct SignalDefinitions by hand, from a database, or from any source you want. Config
support is an optional second module (configurate) layered on top: it walks a generic
ConfigurationNode tree, so it works with any Configurate-supported format (YAML, HOCON, JSON,
GSON) depending on which loader you plug into it.

If you need help, join the discord server.
- Composite signal types out of the box:
message,action-bar,title,sound,effect. - Dot-notation paths (
companion.summon-success) resolved against arbitrarily nested config, with no fixed schema depth. - Fluent
SignalDispatch. Send every configured type,.only(...)a subset,.without(...)an exclusion, to one player or a whole collection. SignalContextplaceholder resolution, decoupled from any specific player/menu context.- Pluggable text rendering via
Serializer. MiniMessage, legacy&codes, plain text, or your own implementation. - Framework-agnostic core. Build
SignalDefinitions programmatically with zero dependency on Configurate. - Optional
configuratemodule for config-driven definitions via recursiveConfigurationNodetree walking, format-agnostic (YAML, HOCON, JSON...). - No external database, no menu dependency. A single-purpose library.
| Dependency | Version |
|---|---|
| Java | 21+ |
| PaperMC | 1.21+ |
| Configurate | 4.2.0 (configurate-core, only required by the configurate module; add a loader like configurate-yaml yourself) |
Add the Bytephoria repository, then pick one dependency depending on your needs. The
configurate module already brings signal transitively, so you don't need to declare both.
It only depends on configurate-core, so you also need to add a concrete loader for whichever
format you're using (configurate-yaml, configurate-hocon, etc.).
repositories {
maven("https://jitpack.io")
}
dependencies {
// Core only: build SignalDefinitions by hand, no Configurate dependency
implementation("com.github.Bytephoria.signal:signal:v1.0.0")
// Config-driven signal definitions (includes signal transitively)
implementation("com.github.Bytephoria.signal:configurate:v1.0.0")
// Pick the loader for your format
implementation("org.spongepowered:configurate-yaml:4.2.0")
}companion:
summon-success:
message: "<green>You summoned <white><companion></white>!"
action-bar: "<gray>Your companion is ready"
title:
title: "<gold>Summoned!"
subtitle: "<gray><companion>"
fade-in: 10
stay: 40
fade-out: 10
sound:
key: "entity.player.levelup"
volume: 1.0
pitch: 1.2final SignalManager signalManager = SignalManager.builder()
.source(new ConfigurateSignalSource(rootNode, MiniMessageSerializer.INSTANCE))
.build();
signalManager.of("companion.summon-success")
.context(SignalContext.builder()
.placeholder("companion", companion.displayName())
.build())
.send(player);- Fork the repository.
- Create a branch:
git checkout -b feature/my-featureorgit checkout -b fix/my-fix - Commit your changes and open a Pull Request.
Please follow the existing code style:
- Use
this.for all instance field references. - Use
finalon parameters, local variables and fields wherever applicable. - Respect the module boundaries.
signalstays framework-agnostic, no Configurate types leak into the core. - No breaking changes to existing SPI interfaces (
SignalComponent,SignalSource,Serializer) without prior discussion.
signal is designed to be a general-purpose player feedback dispatcher, not a menu framework or a plugin-specific tool. Pull requests that push the library toward a specific use case, such as inventory/GUI rendering, event hooks, or a hard dependency on a single config format, will be automatically rejected; that's what your own plugin's integration layer is for. If you need those kinds of features, you have two supported paths:
- Register your own
SignalComponentorSignalSourcevia the SPI. The library is built specifically to be extended without touching its core. - Fork the project if your use case requires tighter integration or custom behavior.
This project is released under the MIT License. You are free to use, modify, and distribute it with attribution.