5.2 KiB
Unified extension packages
packages/<directory>/manifest.json declares exact versions, licenses, dependencies, capabilities, and resources. At startup, the server verifies the entire dependency graph, sizes, SHA-256 hashes, paths, and absence of symlinks. A missing version, cycle, unknown capability, or modified resource prevents startup. Only client and common resources are published; server files have no public route. Resources are verified again when read over HTTP.
Examples are provided in packages/base and packages/trampoline. All images, audio, and models are original. Catalog data comes from official reports and measurements through the public Java 26.2 API; packages contain no vanilla textures or models.
A schema 1 manifest contains:
id, aversionwith three numeric components, andlicense;dependencies:[{id,version}]with exact versions;capabilities, such asblocks.define,client.texture, andserver.on_jump;resources:[{path,scope,role,sha256,size}].
Each resource is limited to 16 MiB; a package to 64 MiB and 128 resources; the package directory to 128 entries. These are server limits; the browser additionally limits the total verified public resources to 128 MiB per connection. Block definitions use the definitions role, and a resource with this role requires schema 1. The server allows up to 4096 additional definitions. A block specifies state as a new namespace:path identifier without properties (lowercase ASCII letters, digits, _, ., and -, plus / in the path), color:[r,g,b], collision:[{min,max}], and an optional render of the same form. Optional opacity is a number from 0…1. If render is omitted, the existing original shape for that state is used, or the collision shape for a new block. Each set may contain at most 64 boxes; the allowed local coordinate range is −2…3. Duplicate definitions and overrides of minecraft:* are rejected. The persistent registry assigns runtime IDs; Game::open extends the catalog with verified definitions before registering them in WorldStore. An ordinary package block without behavior is stored and participates in physics; behavior.server_hook: on_jump binds it to the active WASM provider.
{
"schema": 1,
"blocks": [{
"state": "example:spring",
"color": [97,205,151],
"collision": [{"min":[0,0,0],"max":[1,1,1]}],
"render": [{"min":[0,0,0],"max":[1,1,1]}],
"behavior": {"server_hook":"on_jump"}
}]
}
Module execution
The MVP requires exactly one active provider for the on_jump server hook; no provider or two modules with this role prevents startup. A server .wasm file is declared as a resource with role: "wasm-on-jump" and scope: "server"; the server.on_jump capability is required. The export on_jump: () -> f32 returns a jump impulse in blocks/s. The server calls it only when a player jumps from a block bound to the hook through a verified package definition.
Execution uses Wasmi with no imports, files, network access, or system calls; at most 10,000 fuel units per call, one memory up to 64 KiB, one table up to 128 elements, and one instance. The binary module is limited to 64 KiB. The result must be a finite number from 0…20; a trap or invalid value is recorded in a metric and falls back to a normal jump. The working example returns 10. Tests cover an actual invocation, an infinite loop, excessive memory, an attempted import, and NaN. A separate test creates an example:spring package, verifies its SHA-256, adds a new block to the catalog, registers and persists its runtime ID, binds the block to the module, and receives an impulse of 12 from its own binary WASM module. Duplicates, Minecraft overrides, invalid geometry, opacity/identifiers, and resource changes after loading are rejected.
This is a limited, working extension API, with no claim of arbitrary Forge/Fabric compatibility or WASM access to full world state. A new hook requires an explicit contract version. Spleef in this MVP is implemented as a Rust server mode with persistent rules.
Client resources
/api/manifest returns the public list with URLs, exact versions, sizes, and SHA-256 hashes. The browser downloads files, verifies their sizes and hashes before joining, then stores them in CacheStorage keyed by hash. Cached contents are verified again on subsequent connections. A hash error removes the corrupted entry and prevents joining. The server rejects a mismatched manifest_hash. A public hash does not prove that the client application is unmodified.
The base package provides a pixel texture; the trampoline provides its own texture, a GLSL color function, style settings, and a short synthesized sound. The custom WebGL2 renderer applies them. The core and server contain no graphics engine. Packages do not load arbitrary privileged JavaScript.
When modifying a package, recalculate the size and SHA-256 of each changed resource, increase the version, and update exact dependencies. scripts/catalog_assets.py reproducibly generates the bundled original resources and manifests. The format is designed for a future launcher: it can consume the same manifest and cache by (id,version,sha256); integration with a specific launcher is outside this repository's scope.