API reference
Shader API
Horizon has no shader packs today: the earlier implementation was removed on 2026-10-24. Two things will replace it, designed separately: a Horizon shader API, described here, and a clean-room loader for the existing pack format (its own spec; it is not part of this API). Both sit on the same renderer hooks, agreed between the two.
Overview: what a shader author will be able to do
Write WGSL against documented stages of Horizon's renderer, with typed inputs, options the player can change, a reload as soon as a file is saved and an overlay that shows what each pass costs and draws. The renderer keeps everything that makes it fast (culling, batching, LOD, the mesher); a pack changes how surfaces and light look, not how the world is fed to the GPU.
The design
- A pack is a folder or a zip with
horizon-shaders.toml(id, name, version, theapiline, the stages it uses, its options) and WGSL files. No preprocessor and no other shading language: WGSL is what wgpu validates and compiles for Vulkan, Metal and DirectX 12. - Stages, not pipelines. A stage is a function with a fixed signature that the renderer calls inside its own pass, for example a terrain material (
fn material(input: TerrainInput) -> Surface), the lighting of the visible surfaces, the sky, an optional shadow pass, and a chain of full-screen post passes ending in the frame. A pack that leaves a stage out gets vanilla's look for it. - Typed inputs. Each stage receives structs (the frame: time, camera, sun and moon, weather, fog; the surface: position, normal, block and its light) whose WGSL is generated from the Rust types the renderer uploads. The generated reference lists every field with its unit and range, and a test fails when it drifts.
- Options are WGSL
overrideconstants. The manifest declares each option (on/off, a number in a range, a choice) with its default; the game shows them on the pack's settings screen and sets them when it builds the pipeline. No text substitution, and every option combination is validated the same way. - Hot reload. The game watches the pack's folder. A saved file is validated with naga and the stage rebuilt; on an error the last good version keeps drawing and the error, with its file and line, is shown in the overlay.
- Debug overlay. GPU time per stage and pass (timestamp queries), the targets each pass writes (show any of them full-screen), the pack's options and its compile errors.
- Budgets. A pack declares the targets and passes it needs; the renderer refuses more than its limits, and the benchmark (benchmark-report.md) records the pack and its cost, so "fast" stays measured.
- Off by default. Without a pack the renderer is vanilla's look, and no pack code runs.
The pack format (schema 1)
A pack is a folder, or the same files zipped as a .hshader, with horizon-shaders.toml at its root (crate horizon-shader-api; the sample with every key is crates/horizon-shader-api/tests/samples/schema-1/):
schema = 1 # the manifest's format; a reader refuses schemas newer than it knows
id = "soft_light" # [a-z0-9_]{1,64}: the settings key and the registry id
name = "Soft Light"
version = "1.0.0"
api = "0.1" # the shader API line the WGSL is written for
description = "..." # optional, like authors and license
shared = ["common.wgsl"] # optional: WGSL put before every stage's file, in order
[sky] # each stage is optional, but a pack has at least one
file = "sky.wgsl"
[material]
file = "material.wgsl"
[[post]] # full-screen passes, in the order they run (8 at most)
file = "post/grade.wgsl"
name = "Colour grade" # optional: the GPU time overlay's label
[[options]] # 64 at most; `id` is the WGSL `override` it sets
id = "saturation"
name = "Saturation"
type = "float" # bool, float (min, max, step), int (min, max), choice (values)
default = 1.1
min = 0.0
max = 2.0
step = 0.05
[budget]
gpu_ms = 1.5 # optional: the GPU time the pack aims to add (0 to 16 ms)
An option's override has the type of its kind: bool, f32, i32, or u32 for a choice (the index of the value). The pack holds only the manifest, the .wgsl files it names (each used, UTF-8, 256 KiB at most), README.md, LICENSE (.md, .txt) and icon.png, under plain paths, 8 MiB in all. A .hshader is built the same way every time (files in path order, fixed dates), so a pack's SHA-256 depends only on its files.
Guide, reference and examples
- shaders-reference.md: every stage's signature, input and output structs, resources and helpers, the frame's fields with their units, option types and limits, generated from
crates/horizon-shader-api. - The guide: making a pack with
horizon-shader new,checkandpack; the templates and the example pack (crates/horizon-shader-api/packs/golden_hour).
Stability
Not started. The first stages will be experimental (opt-in), then preview once a reference, an example and a test pack exist (stability.md).
Not there yet
Option values other than the defaults (the three stages run, with hot reload), then the overlay, lighting and shadow stages.
Changelog
- 2026-10-26: the material stage in the game: terrain's surfaces through the pack's
material. - 2026-10-26: the sky stage in the game: the pack's
skygets vanilla's colour along each ray. - 2026-10-26: the post stage in the game (
HORIZON_SHADER_PACK, hot reload with the last good pack kept). - 2026-10-25:
horizon-shader(new,check,pack), three templates, the example pack and the guide. - 2026-10-25: the check (naga validation, signatures, options, budgets, SPIR-V/Metal/HLSL translation).
- 2026-10-25: the stages of API 0.1 (sky, material, post), their inputs and the generated reference.
- 2026-10-25: the pack format, schema 1:
horizon-shaders.tomland the.hshaderpackage. - 2026-10-24: the earlier shader pack code was removed; this API is designed from scratch.
Edit this page on GitHub · Spotted something wrong? Open an issue or ask on Discord.
Not an official Minecraft product. Not approved by or associated with Mojang or Microsoft.