š Shamoo v0.1.0 is here
It's our first release, baby.
After months of designing, rewriting, deleting, rewriting again, and convincing an orca that Java and TypeScript can coexist, Shamoo v0.1.0 is finally here.
Shamoo is another way to build Minecraft plugins, but it exists because we believe plugin development can be simpler, safer, and more enjoyable without abandoning Paper or Velocity.
What is Shamoo?
Shamoo lets you write Minecraft plugins in TypeScript and run them through a Java 21 runtime for Paper and Velocity.
Development happens with familiar TypeScript tooling. shamoo build compiles a plugin into a three-file ESM installation:
dist/
āāā index.js
āāā index.js.map
āāā shamoo-plugin.json
On the server, ShamooRuntime loads each plugin generation into an embedded, in-process Node runtime powered by Javet.
There is no external Node process and no TypeScript compilation during server startup. Plugins are built before deployment and interact with the server through explicit, data-oriented platform boundaries.
Or, as the orca puts it:
Why write Java when you can make Java run JavaScript?
What ships in v0.1.0?
This release establishes the foundation of the Shamoo ecosystem:
- š Separate ShamooRuntime JARs for Paper and Velocity
- ā” Ahead-of-time TypeScript compilation and bundling
- š¦ Three-file plugin installations with strict manifests
- š„ Watched, transactional plugin replacement
- š Generated types for pinned Paper and Velocity APIs
- šÆ Lifecycle, event, command, and scheduling decorators
- š ļø Project scaffolding, diagnostics, builds, and development watching
- š§© A standalone dependency-injection container and compiler injection metadata
- š Universal bundles that can target Paper and Velocity
- š¦ 34 reusable
@shamoo/* libraries
- š 13 published source examples
- š Eight ready-to-run example installations
Paper and Velocity use different Runtime JARs, but a TypeScript plugin can target both platforms from one source project.
A real Paper plugin
This example uses the APIs included in v0.1.0:
import { Command, Context } from '@shamoo/commands';
import { Plugin } from '@shamoo/decorators';
import { OnDisable, OnEnable } from '@shamoo/lifecycle';
import type { PaperCommandContext } from '@shamoo/paper';
import { OnPlayerJoinEvent } from '@shamoo/paper-raw';
interface PaperRuntimeEvent {
readonly type: string;
readonly asynchronous: boolean;
}
@Plugin({ name: 'welcome-aboard' })
export class WelcomeAboardPlugin {
private joins = 0;
@OnEnable()
public enabled(): void {
console.info('[welcome-aboard] Plugin enabled.');
}
@OnPlayerJoinEvent()
public playerJoined(@Context() event: PaperRuntimeEvent): void {
this.joins += 1;
console.info(
`[welcome-aboard] Received ${event.type}; total joins=${String(this.joins)}`,
);
}
@Command('shamoo-status')
public async status(
@Context() context: PaperCommandContext,
): Promise<void> {
await context.reply(`Observed ${String(this.joins)} player join event(s).`);
}
@OnDisable()
public disabled(): void {
console.info('[welcome-aboard] Plugin disabled.');
}
}
There is no @Listener decorator. Platform events use generated decorators such as @OnPlayerJoinEvent(), while command responses are sent explicitly through their command context.
Typed commands
Shamoo's Paper command layer supports typed routes, parsers, suggestions, options, senders, and rich responses:
import {
Argument,
Command,
Context,
Option,
Sender,
type CommandSender,
type Player,
} from '@shamoo/commands';
import { Plugin } from '@shamoo/decorators';
import { miniMessage, type PaperCommandContext } from '@shamoo/paper';
@Plugin({ name: 'greetings' })
export class GreetingsPlugin {
@Command('shamoo-greet [player] [message...]', {
aliases: ['sgreet'],
description: 'Greet an online player.',
})
public async greet(
@Argument('player', {
parser: 'player',
suggestions: ['players'],
})
player: Player | undefined,
@Argument('message') message: string | undefined,
@Option('uppercase', {
aliases: ['u'],
parser: 'boolean',
})
uppercase: boolean | undefined,
@Sender() sender: CommandSender,
@Context() context: PaperCommandContext,
): Promise<void> {
const recipient = player?.name ?? sender.name;
const text =
uppercase === true
? (message ?? 'Hello').toUpperCase()
: (message ?? 'Hello');
await context.reply(
miniMessage(
'<gold><greeting></gold>, <aqua><recipient></aqua>!',
{
placeholders: {
greeting: text,
recipient,
},
},
),
);
}
}
The richer parser and UI command APIs are currently Paper-specific. Velocity has its own command boundary rather than pretending both platforms expose identical behavior.
One project, two platforms
A universal project declares separate lazy platform entrypoints:
{
"name": "my-universal-plugin",
"platforms": ["paper", "velocity"],
"entrypoint": "src/plugin.ts",
"paperEntrypoint": "src/paper.ts",
"velocityEntrypoint": "src/velocity.ts",
"tsconfig": "tsconfig.json",
"outDir": "dist"
}
Platform-neutral components live in src/plugin.ts. Paper-only and Velocity-only imports belong in their respective entrypoints.
The resulting three-file installation can be copied to either Runtime host. The inactive platform graph is not evaluated.
Transactional reloads
ShamooRuntime watches complete plugin installation directories.
When an installation changes, the Runtime:
- Waits for a stable three-file candidate.
- Validates its manifest and compatibility.
- Starts a separate replacement generation.
- Runs
load, enable, and ready.
- Keeps the existing generation active if preparation fails.
- Drains and disables the old generation after the replacement is ready.
This is whole-generation replacement, not JavaScript module HMR.
shamoo dev rebuilds when source files change, but it does not deploy files to a server automatically. Your development setup must copy or synchronize the complete dist directory into the Runtime's watched plugin root.
Getting started
Requirements
For development:
- Node.js 22 or newer
- pnpm 10 or newer
For the server:
- Java 21
- Linux x86-64
- A supported Paper or Velocity build
Install the CLI from the Shamoo registry:
npm install --global @shamoo/[email protected] \
--registry=https://shamoof.com/npm/
Create a project:
shamoo create my-plugin \
--name @example/my-plugin \
--platform paper
cd my-plugin
Route Shamoo packages to the Shamoo registry:
printf '%s\n' \
'@shamoo:registry=https://shamoof.com/npm/' \
> .npmrc
Install, diagnose, and build:
pnpm install
pnpm doctor
pnpm build
shamoo create generates the project files but deliberately does not install dependencies or run package lifecycle scripts.
Installing a plugin
First, install the matching ShamooRuntime JAR in the server's normal plugin directory.
Then copy the complete TypeScript plugin installation into the Runtime's watched root:
Paper:
<server>/plugins/ShamooRuntime/plugins/<plugin-id>/
Velocity:
<server>/plugins/shamooruntime/plugins/<plugin-id>/
The plugin directory must contain:
index.js
index.js.map
shamoo-plugin.json
Do not place those files directly in the server's general plugins directory. That directory is for the platform-specific ShamooRuntime JAR.
Compatibility
The initial stable release deliberately targets a narrow, tested matrix:
- Java 21
- Linux x86-64
- Paper 1.21.8 build 55
- Velocity 3.4.0
- Exact-version Paper NMS and packet support where explicitly enabled
The distributed Runtime currently embeds a Linux x86-64 Javet native runtime. Windows, macOS, and ARM builds are not part of v0.1.0.
Generated declarations also do not mean arbitrary JVM objects are exposed directly to JavaScript. Runtime integrations use selected, mediated operations and data-only values across the isolate boundary.
ShamooRuntime is defense in depth, not an operating-system security sandbox.
Packages and examples
The release includes reusable libraries under @shamoo/* and source examples under @shamoo/example-*.
Eight examples are also available as ready-to-run three-file installations:
- Commands
- Complete Paper plugin
- Complete Velocity plugin
- Configuration
- Dual-platform plugin
- Economy
- Folia scheduling
- Hello world
Additional examples for cross-plugin services, custom events, reload behavior, proxy routing, and testing are source demonstrations. They are not advertised as ready-to-run server plugins until their remaining Runtime boundaries are integrated.
Documentation
The previously proposed docs.shamoof.com and github.com/Shamoof/Shamoo/wiki links are not used because they do not currently resolve.
Why build this?
Minecraft plugin development has been thriving for more than a decade.
During that time:
- TypeScript became a standard application-development language.
- Package managers and build tools improved dramatically.
- IDE feedback became faster and more precise.
- Developers came to expect reproducible builds and rapid iteration.
Shamoo explores what those workflows can look like for Minecraft without replacing the Paper and Velocity ecosystems underneath them.
The goal is not to hide every platform difference. It is to make those differences explicit, typed, and easier to work with.
What's next?
The next milestones include:
- Broader host and native-platform support
- More safely mediated Paper and Velocity operations
- Deployment tooling around
shamoo dev
- Complete bundled consumer wiring for cross-plugin services
- Production authoring support for proxy routing and state migration
- Deeper Runtime integration for configuration and dependency injection
- More documentation and ready-to-run examples
These are directions, not promises that they already ship in v0.1.0.
The orca
Why an orca?
Because orcas are intelligent, collaborative, adaptable, and unusually effective in their environment.
It felt appropriate.
š
Contributing
Issues, ideas, documentation improvements, and pull requests are welcome:
If you find a bug, there is a reasonable chance we already know about it.
If you fix it first, we will pretend that was the plan all along.
Star the project ā
If Shamoo looks interesting, star the repositories:
It helps more people discover the project and keeps the orca well-fed.
See you in the next release.
š