-
Notifications
You must be signed in to change notification settings - Fork 0
Selfhosting
Everything mcwidgets serves is static. If you can host a directory of files, you can host the widgets, and your embeds stop depending on someone else's uptime, version choices, and traffic logs.
The repository has one command that assembles the whole site, and the same command backs the container image and the GitHub Pages deployment. There is no second definition of the layout to keep in sync.
git clone https://github.com/KabanFriends/mcwidgets.git
cd mcwidgets
npm ci
npm run build
npm run stage
You need Node 20.19 or later, or Node 22.12 or later.
npm run build compiles the widget modules and the preprocessors. npm run stage assembles them into .host/, which is the site. Copy that directory to any static web server and you are done.
npm run stage deletes .host/ before writing it. Add your own files after staging, not before.
.host/
index.html a landing page with both widgets embedded
advancements/
embed.html iframe shell
viewer.js ES module
assets/ window, tab, frame, and background textures
itemgui/
embed.html iframe shell
itemgui.js ES module
assets/ slot highlight and tooltip textures
core/ one shared copy of the font and tooltip sprites
bundles/ demo bundles, if you built them
Each widget directory is self-contained. viewer.js finds its textures and its font in the assets/ beside it, which is why an embed needs no assetBase. Keep those two together when you move things around, and core/ stays available for hosts that would rather point every widget at one shared copy with coreAssetBase.
Every URL inside the tree is relative. The site is correct at a domain root and under a subdirectory alike, so https://widgets.example.com/ and https://example.com/mcwidgets/ both work with no configuration.
The bundles/ directory holds the demo content and is optional. Build your own with the preprocessors and drop them anywhere the tree can reach:
npm run stage
node packages/advancements/bin/mcw-adv-preprocess.mjs \
--input ~/server/datapacks/my_pack \
--output .host/bundles/my-pack
Then embed them, with the bundle named relative to the shell:
<iframe
src="https://widgets.example.com/advancements/embed.html?bundle=../bundles/my-pack/bundle.json"
style="width: 100%; height: 420px; border: 0;"
></iframe>bundle resolves against embed.html, and the textures and the font resolve against viewer.js beside it, so everything comes from your own host and the whole embed is same-origin with the shell. Cross-origin headers never enter into it. That is the main practical reason to self-host.
See Building advancement bundles and Building item GUI bundles.
The staged tree includes bundles/ only if the demo bundles exist. To build them, which downloads the vanilla advancement JSON and every icon it references:
npm run fetch-demo-data -w @mcwidgets/advancements
npm run preprocess:vanilla -w @mcwidgets/advancements
npm run preprocess:demo -w @mcwidgets/itemgui
npm run stage
fetch-demo-data lists files through the GitHub API, which allows 60 unauthenticated requests an hour. Set GITHUB_TOKEN if you hit the limit.
npm run host
This stages the site and serves it on port 8080, binding all interfaces so another machine on the network can open it. The startup log prints the URLs, including one per network interface. Pass a different port with npm run host -- --port 3000.
Use it for development. It sends Cache-Control: no-cache and no cross-origin headers at all, so it is not a production server.
Serve .host/ as-is. Four things matter.
Cross-origin headers. Everything served is public static content, and the whole point is that someone else's page loads it. Both import of a cross-origin ES module and fetch of a bundle.json need Access-Control-Allow-Origin. Send *.
add_header Access-Control-Allow-Origin "*" always;
Neither request is preflighted, so there is no OPTIONS handler to write.
Cross-Origin-Resource-Policy. A page that turns on COEP blocks these subresources even when CORS allows them. Send cross-origin so those embedders work.
add_header Cross-Origin-Resource-Policy "cross-origin" always;
Font MIME types. The default pixel font is a .ttf. Some servers do not know the type and send application/octet-stream, which browsers refuse to use as a font.
Compression. bundle.json and the widget modules compress well. A vanilla advancement bundle is mostly repeated keys. PNG and TTF are already compressed, so leave them alone.
The repository ships an nginx configuration at docker/default.conf that does all four, plus a /healthz probe endpoint. Read it even if you use a different server, since it is short and it is the reference for what the widgets expect.
The repository includes a Dockerfile that copies the staged tree into nginx with that configuration.
npm run build
npm run stage
docker build -f docker/Dockerfile -t mcwidgets .
docker run -p 8080:80 mcwidgets
.dockerignore narrows the build context to .host/ and docker/, so the image is the site and nothing else.
Prebuilt images are published to ghcr.io/kabanfriends/mcwidgets, tagged by branch and build time. Pick a tag explicitly. There is no moving tag to follow.
The repository includes a workflow that builds the site, builds the demo bundles, stages, and deploys to GitHub Pages on every push to master. To use it in your fork, set Source to GitHub Actions in the repository's Pages settings.
A project site is served from /<repo>/ rather than a domain root. Nothing in the tree cares, because every URL in it is relative.
packages/mcassets/mc-version.json names the Minecraft version that every build-time download and every bundle's metadata is pinned to. Editing that one file moves both. It is what makes two runs of the same input produce the same output.
Minecraft textures and fonts are © Mojang Studios. Self-hosting means redistributing them, so follow Mojang's usage guidelines.
Embedding
Reference
Building bundles
Running it yourself