Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/scripts/verify-modrinth.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@
"mc1.21.11-neoforge": ("neoforge", "1.21.11"),
"mc26.1.2-neoforge": ("neoforge", "26.1.2"),
"mc26.2-neoforge": ("neoforge", "26.2"),
"mc26.2-fabric": ("fabric", "26.2"),
"mc26.3-fabric": ("fabric", "26.3"),
"mc26.3-neoforge": ("neoforge", "26.3"),
}


Expand Down
10 changes: 7 additions & 3 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,21 @@ jobs:
# broken on both 26 targets for months precisely because nothing
# booted one in CI.
- version: 26.2-neoforge
java: '25'
smoke: true
- version: 26.1.2-neoforge
java: '25'
smoke: true
- version: 26.2-fabric
- version: 26.3-fabric
- version: 26.3-neoforge
steps:
- uses: actions/checkout@v4

# Both: Loom needs 25 to configure any target, the pre-26 ones compile against 21.
- uses: actions/setup-java@v4
with:
java-version: ${{ matrix.java || '21' }}
java-version: |
21
25
distribution: temurin
cache: gradle

Expand Down
101 changes: 92 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ jobs:
chmod +x gradlew
./gradlew :1.20.1-fabric:build :1.21.1-fabric:build :1.21.11-fabric:build \
:1.21.1-neoforge:build :1.21.11-neoforge:build \
:26.1.2-neoforge:build :26.2-neoforge:build --no-daemon
:26.1.2-neoforge:build :26.2-neoforge:build :26.2-fabric:build \
:26.3-fabric:build :26.3-neoforge:build --no-daemon
env:
GRADLE_OPTS: -Xmx2g

Expand Down Expand Up @@ -180,7 +181,6 @@ jobs:
version: ${{ steps.meta.outputs.version }}+mc1.21.1-neoforge
version-type: release
loaders: neoforge
dependencies: rinku(required)
game-versions: '1.21.1'
changelog: ${{ steps.notes.outputs.body }}
files: versions/1.21.1-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar
Expand All @@ -196,7 +196,6 @@ jobs:
version: ${{ steps.meta.outputs.version }}+mc1.21.11-neoforge
version-type: release
loaders: neoforge
dependencies: rinku(required)
game-versions: '1.21.11'
changelog: ${{ steps.notes.outputs.body }}
files: versions/1.21.11-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar
Expand All @@ -212,7 +211,6 @@ jobs:
version: ${{ steps.meta.outputs.version }}+mc26.2-neoforge
version-type: release
loaders: neoforge
dependencies: rinku(required)
game-versions: '26.2'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.2-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar
Expand All @@ -228,11 +226,55 @@ jobs:
version: ${{ steps.meta.outputs.version }}+mc26.1.2-neoforge
version-type: release
loaders: neoforge
dependencies: rinku(required)
game-versions: '26.1.2'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.1.2-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.2 Fabric to Modrinth
if: steps.check.outputs.release == 'true' && steps.check.outputs.fabric == 'true'
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: tDw1xQja
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
modrinth-featured: false
name: WebGUI ${{ steps.meta.outputs.version }} (26.2 Fabric)
version: ${{ steps.meta.outputs.version }}+mc26.2-fabric
version-type: release
loaders: fabric
game-versions: '26.2'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.2-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.3 Fabric to Modrinth
if: steps.check.outputs.release == 'true' && steps.check.outputs.fabric == 'true'
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: tDw1xQja
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
modrinth-featured: false
name: WebGUI ${{ steps.meta.outputs.version }} (26.3 Fabric)
version: ${{ steps.meta.outputs.version }}+mc26.3-fabric
version-type: beta
loaders: fabric
game-versions: '26.3'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.3-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.3 NeoForge to Modrinth
if: steps.check.outputs.release == 'true' && steps.check.outputs.neoforge == 'true'
uses: Kir-Antipov/mc-publish@v3.3
with:
modrinth-id: tDw1xQja
modrinth-token: ${{ secrets.MODRINTH_TOKEN }}
modrinth-featured: false
name: WebGUI ${{ steps.meta.outputs.version }} (26.3 NeoForge)
version: ${{ steps.meta.outputs.version }}+mc26.3-neoforge
version-type: beta
loaders: neoforge
game-versions: '26.3'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.3-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

# CurseForge — mirrors the Modrinth uploads. Only runs when the CURSEFORGE_ID
# repo variable is set, and never blocks the (gated) Modrinth release:
# every step is continue-on-error.
Expand Down Expand Up @@ -294,7 +336,6 @@ jobs:
loaders: neoforge
game-versions: '1.21.1'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/1.21.1-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 1.21.11 NeoForge to CurseForge
Expand All @@ -310,7 +351,6 @@ jobs:
loaders: neoforge
game-versions: '1.21.11'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/1.21.11-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.2 NeoForge to CurseForge
Expand All @@ -326,7 +366,6 @@ jobs:
loaders: neoforge
game-versions: '26.2'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/26.2-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.1.2 NeoForge to CurseForge
Expand All @@ -342,9 +381,53 @@ jobs:
loaders: neoforge
game-versions: '26.1.2'
changelog: ${{ steps.notes.outputs.body }}
dependencies: rinku(required)
files: versions/26.1.2-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.2 Fabric to CurseForge
if: steps.check.outputs.release == 'true' && steps.check.outputs.fabric == 'true' && vars.CURSEFORGE_ID != ''
continue-on-error: true
uses: Kir-Antipov/mc-publish@v3.3
with:
curseforge-id: ${{ vars.CURSEFORGE_ID }}
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
name: WebGUI ${{ steps.meta.outputs.version }} (26.2 Fabric)
version: ${{ steps.meta.outputs.version }}+mc26.2-fabric
version-type: release
loaders: fabric
game-versions: '26.2'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.2-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.3 Fabric to CurseForge
if: steps.check.outputs.release == 'true' && steps.check.outputs.fabric == 'true' && vars.CURSEFORGE_ID != ''
continue-on-error: true
uses: Kir-Antipov/mc-publish@v3.3
with:
curseforge-id: ${{ vars.CURSEFORGE_ID }}
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
name: WebGUI ${{ steps.meta.outputs.version }} (26.3 Fabric)
version: ${{ steps.meta.outputs.version }}+mc26.3-fabric
version-type: beta
loaders: fabric
game-versions: '26.3'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.3-fabric/build/libs/!(*-@(dev|sources|javadoc)).jar

- name: Publish 26.3 NeoForge to CurseForge
if: steps.check.outputs.release == 'true' && steps.check.outputs.neoforge == 'true' && vars.CURSEFORGE_ID != ''
continue-on-error: true
uses: Kir-Antipov/mc-publish@v3.3
with:
curseforge-id: ${{ vars.CURSEFORGE_ID }}
curseforge-token: ${{ secrets.CURSEFORGE_TOKEN }}
name: WebGUI ${{ steps.meta.outputs.version }} (26.3 NeoForge)
version: ${{ steps.meta.outputs.version }}+mc26.3-neoforge
version-type: beta
loaders: neoforge
game-versions: '26.3'
changelog: ${{ steps.notes.outputs.body }}
files: versions/26.3-neoforge/build/libs/!(*-@(dev|sources|javadoc)).jar

# mc-publish can report success without actually creating a version (e.g.
# a token lacking the "Create versions" scope). Confirm every version is
# really on Modrinth so a green run can't lie.
Expand Down
35 changes: 35 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
# Changelog

## 2.0.0 - 2026-10-13

A major version for one reason: WebGUI no longer depends on another mod. Nothing in the page
API changed and the network protocol is the same, so existing pages keep working and a 2.0.0
client still talks to a 1.8.x server.

### Added
- **Minecraft 26.2 on Fabric, and 26.3 on both loaders.** 26.3 is published as a beta: the game itself is still in snapshots, and it replaced GLFW with SDL and moved the GPU API out of `blaze3d`, so the parts of this mod that touch the window and the screen are new there.

### Changed
- **The update check is built in and always runs.** The server asks Modrinth on start whether a newer WebGUI exists for its Minecraft version and loader, and falls back to GitHub releases if Modrinth cannot be reached. It used to do nothing at all unless an operator found `updateCheckUrl` and filled in an endpoint of their own, which almost nobody did.
- Operators are also told in chat when they join, so an update is not something only the start-up log knows. Set `updateNotifyInChat` to `false` to keep the console notice and drop the chat one. Ordinary players are never told.
- **`updateCheckUrl` is gone.** The address is fixed in the mod now. A config that still has the key is not an error; it is ignored.
- **A page URL must now name a scheme the mod will open:** `webgui://`, `https://`, `http://`, `wss://` or `ws://`. Anything else is refused with a line in the log instead of being handed to the browser — a URL arrives from a server, and `file://` would read the player's disk while `javascript:` would run inside whatever page is open.
- `webgui:name.html` and `webgui:/name.html` used to mean the same as `webgui://name.html` and no longer do. One spelling is easier to check than three. Settings that use the old form need the two slashes.
- **A server now starts with a HUD page as well as a full-screen one.** `config/webgui/web/hud.html` is created beside `index.html` on first start: a small corner card naming the keys — <kbd>F6</kbd> for the main menu, <kbd>`</kbd> to interact with the overlay, <kbd>F12</kbd> for developer tools — and linking to webgui.space. It paints no background of its own, which is what an overlay drawn over the world has to do.
- It is shown on join out of the box: `autoHudUrl` points at it and `autoHudOnJoin` is now on unless the config says otherwise. A server that set either of them keeps what it set.
- **The mod's settings screen now explains itself.** Every option has a tooltip saying what it does and what it costs, in the spirit of the game's own video settings, and two more settings are there instead of only in the config file:
- **Ask where to save downloads.** Off, a file goes into `webgui-downloads/` and the name is said in chat; on, the system save dialog opens for each one. The engine could always do this and the mod never offered it.
- **Let pages play sound on their own.** Off by default, as it already was: video and audio wait for a click, the way a browser treats a tab you did not open.
- **Page frame rate** was in the config file and nowhere else; it is now a setting like the rest.
- The screen used to tell everyone to add `--remote-debugging-port=9222` to their launcher. That was true of the old browser library, whose command line was fixed before any mod ran; this one takes the port from the mod, so the advice was for a problem that no longer exists. The inspector's address is shown when it is actually listening, and only while the developer tools are on.
- **Scrolling a page starts at 25 notches instead of 7,** and the setting now goes to 40. Seven was picked to fix a wheel that barely moved, and it still read as slow on a long page. A client that already has the setting saved keeps its own value; it is in the mod's settings screen either way.
- **The main-menu key no longer opens `example.com`.** That placeholder was what a player saw after installing the mod and pressing the key on the title screen, where no server has sent any settings yet. It now opens webgui.space, which at least says what the key is for.
- **`mainMenuUrl` now points at the server's own page out of the box.** A fresh server writes `webgui://index.html` into its config, which is the starter page it also creates, so the key that opens the main menu shows something of the server's from the first launch instead of `example.com`. A config that already has the setting is left alone.
- **WebGUI no longer needs another mod to run.** The embedded browser is part of WebGUI now instead of being provided by a separate library mod, so installing WebGUI is one file and nothing else. Chromium itself is still downloaded once per machine on first start, outside the game directory, and shared by every instance.

### Fixed
- **The custom death screen on Fabric 26.2 and later.** It hooked a method the game no longer has, which the mixin configuration treats as fatal — the game would not start at all on those versions.
- **The game can be closed again.** Quitting left two threads running — the page server and Chromium — so the process never exited: silently on 1.21.1 and earlier, and from 1.21.11 as a crash report written by the game's own shutdown watchdog.
- **Typing into a page on 26.3.** SDL only delivers typed characters while text input has been started, and the game starts it for its own text fields. Keys arrived and shortcuts such as Ctrl+A and Ctrl+V worked, but letters did not reach the page.
- **Cursor shapes on 26.3.** The cursor is now decided once per frame by the game, so setting it directly was overwritten before it could be seen.
- **Enter in a page.** It never produced a character event, on any version, so a `textarea` took every key but this one and a form could not be submitted with it.
- A NeoForge warning on every launch of 26.3 about deprecated mod metadata.

## 1.8.1 - 2026-09-12

### Fixed
Expand Down
75 changes: 75 additions & 0 deletions MODRINTH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
**Your web app, running inside Minecraft.**

WebGUI opens a real web page in the game — as a full-screen interface or as a transparent overlay on top of gameplay. Not a reskinned inventory, not another UI framework to learn: actual HTML, CSS and JavaScript, rendered by actual Chromium.

If you can build a website, you can build a Minecraft interface.

<iframe width="560" height="315" src="https://www.youtube-nocookie.com/embed/wqZ400GWKUw" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

## What people build with it

* **Server shops** that look like an online store, with images, search and a cart
* **Quest journals and codexes** with real typography and layout
* **Live maps** — Leaflet or your own canvas, following the player as they walk
* **HUD overlays** — team scores, timers, health bars, a minimap, drawn over the world
* **Admin panels** for staff, with the same dashboard you already run in a browser
* **Custom death screens** that say who killed you and let you respawn
* **Launch menus** and lobby screens with your server's own branding
* **Entire in-game apps** — anything you would otherwise build as a web app

## Why it feels different

Everything you already use keeps working. React, Vue, Svelte or plain JavaScript. Tailwind. Your component library. Your animations, your API, your WebSocket. You develop in a browser with hot reload, then point the mod at the page — and it looks exactly the same in the game.

The page is not a decoration, either. It knows who is looking at it and what is happening around them — the player's name, health, food, position, where they are looking, which block or mob is under the crosshair — updated as they move. And it can talk back: a click in the page becomes an event on the server, so a shop can actually sell, and a button can actually run a command.

```js
// This is the whole integration
window.webgui.on('client', player => {
document.title = `${player.username} — ${player.health} HP`;
});

window.webgui.postToGame({ channel: 'shop:buy', item: 'diamond' });
```

For React, Vue and Svelte there is one package with hooks and stores ready to go:

```bash
npm i @webgui/client
```

## You don't even need a web host

Put your files in a folder on the server and point the mod at them. They travel down the same connection the player is already on — no domain, no hosting bill, no port to open, works behind NAT. Edit a file, run one command, and the page a player has open refreshes in front of them.

Prefer your own host? Nothing changes: an `https://` address works exactly as it always did, and the two mix freely.

## For server owners

Opening a page is one command:

```
/webgui gui @a https://your-site.example/shop
/webgui hud @a webgui://hud.html
```

Pages can also be bound to an entity, so right-clicking a villager opens your shop with that villager's context. Every URL the mod opens carries a signed token, so your backend knows which player is asking without a login screen. Players without the mod are told what they are missing instead of quietly seeing nothing.

## Compatibility

| Minecraft | Loader |
|-----------|--------|
| 26\.2 · 26\.1.2 | NeoForge |
| 1\.21.5 – 1.21.11 | Fabric · NeoForge |
| 1\.21 – 1.21.1 | Fabric · NeoForge |
| 1\.20.1 | Fabric |

Minecraft 26 is NeoForge-only for now — Fabric is waiting on Yarn mappings for 26.x.

**Installing:** on Fabric you need Fabric API, and that is it — the browser ships inside the jar. On NeoForge, add [Rinku](https://modrinth.com/mod/rinku) alongside it; launchers pick it up automatically. Chromium (~150 MB) downloads itself on first launch. Java 21, or Java 25 for Minecraft 26.

## Links

* **Documentation** — <https://webgui.space> — guides, the full API, and examples you can paste
* **GitHub** — <https://github.com/mc-webgui/webgui> — issues and source
* **npm** — <https://www.npmjs.com/package/@webgui/client>
Loading
Loading