Read-only file browse was only reachable by typing the URL. Add
site.filesUrl (files.${BASE_DOMAIN}) plus nav/hero labels in en/es/eu,
and surface it as a nav link and a secondary hero CTA beside "Cómo entrar".
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Remove the stat-grid from the status section (server card only); prune the
now-orphaned site.stats, MOD_COUNT_KEY, statLabels (3 locales), and
.stat-grid/.tile CSS.
- Empty-roster message -> "Nobody online", now localized (status.empty in
en/es/eu) and wired to both ServerCard instances.
- Flatten the server-card icon (drop the inset emboss bevel on .sc-icon).
- Drop "Solo LAN" (hero metaLan) from the hero meta row; prune metaLan (3 locales).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- landing header + footer brand: swap the Creeper pixel-art for the
ulicraft-logo-mini.svg goat mark.
- ServerCard fallback icon: same logo (real SLP favicon still overrides on
a successful ping).
- minecraft: set ICON=/extras/server-icon.png + OVERRIDE_ICON so the
in-game server-list entry and the SLP favicon use the goat logo. PNG
ships in ./runtime (mounted /extras).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The build-time download buttons baked stale/placeholder URLs (the host has no
synced launcher.json, so the build fell back to launcher.example.json). Render
a skeleton at build time instead and fetch the live launcher.json client-side
once on page load (no polling) from
https://distribution.${BASE_DOMAIN}/launcher/launcher.json, building per-OS
buttons from files[]. On fetch error the skeleton clears.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Members roster avatars render 230px tall (full body); NMSR size bumped to 256
and tiles widened to fit the portrait.
- Features section is now two columns: the 4 feature cards stacked on the left, a
Minecraft goat image on the right (public/Goat_JE1_BE1.webp). Stacks on narrow
screens.
- Header nav links trimmed to How to Join + Status; the auth CTA cluster is now
Register / Account / Play (the old "Log in" button relabeled Account →
Cuenta/Kontua).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Default language Spanish at root /, English moves to /en/ (eu unchanged):
getStaticPaths {lang:undefined}->es + LANG_*_PATH maps swapped in ui.ts.
- Section order: hero -> join -> status -> members -> mods -> features.
- Join flow 3 -> 2 steps (drop the Connect/IP step; launcher handles the
address). Remove the hero IP CopyChip. Header CTA renamed Play/Jugar/Jolastu
and gains Register + Login links on all four pages.
- Account page: hide the whole login block once authenticated (not just the
form), add an avatar Refresh button (cache-busted NMSR re-fetch), flatten the
avatar (no bevel). New i18n key account.refresh.
- Register page: new REGISTRATION_SHOW_INVITE env (default false/hidden) toggles
the invite-code field independently of the REGISTRATION_MODE backend gate.
- Members roster: drop the `admin` account, render full-body via a new
ROSTER_AVATAR_MODE (default fullbodyiso); portrait tiles.
- Style: flatten emboss on feature icons (.picon) + player tiles (.roster-tile).
PixelIcon gains optional image support (/icons/<name>.png|svg).
- Favicon now /favicon.png (committed) on all pages.
- Docs: plan/09-landing.md Assets section (logo/favicon/features-icons drop
points) + default-language note; .env.example documents the two new vars.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Execute plan/18 (WS1-6) + plan/17.
- WS1: homepage join = 3 steps off packwiz (register -> UlicraftLauncher
-> join); per-OS downloads from a synced launcher-manifest.json (schema +
example committed); Fjord moved to its own /fjord page. Drop packwizUrl.
- WS2/3: mc-status gains an isolated /players endpoint (admin login ->
Drasl GET /players, own client+TTL+token cache, never blocks the status
path); online + registered rosters render shared name+avatar tiles;
AVATAR_MODE env (default headiso).
- WS4: /account skin CRUD via browser-direct Drasl (login -> upload ->
reset), in-memory token, players[0]; register relinks "Manage it here".
- WS5: footer link to status.${BASE_DOMAIN} in every footer.
- WS6: tooling/build-modlist.py generates mods.json + extracted logos from
the distribution forgemods; ModList.astro renders a flat list; stat tile
fed from the count.
Manifest/mods loaders read at build with a process.cwd() fallback (the
import.meta.url-only path does not resolve in Astro's bundled build).
New env: AVATAR_MODE, DRASL_ADMIN_USERNAME, DRASL_ADMIN_PASSWORD (mc-status
only). Generated mods.json / launcher-manifest.json / logos are gitignored;
.example.json files document the shapes. Build: 12 pages; mc-status builds.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a featured live ServerCard to the landing (replaces the static
ServerListPanel in hero + status sections): server favicon, color MOTD,
online/offline pill, players online/max with fill bar, and a player-head
row rendered by our own NMSR from Drasl skins. Progressive enhancement —
SSG skeleton degrades gracefully when JS or the API is unavailable.
Back it with a self-hosted pinger instead of the public api.mcstatus.io:
mcstatus.io's API service is closed-source (only the mcutil library is
open), so docker/mc-status wraps mcutil and re-emits its v2 JSON shape,
keeping the frontend unchanged. The service ignores the path address and
only pings MC_STATUS_TARGET (no SSRF relay), with a 30s TTL cache.
Exposed same-origin via caddy at the apex /api/mcstatus/* path (no new DNS
subdomain or LE cert change, no CORS). Uptime Kuma stays the uptime
history + alerting backend; see plan/15-mc-status.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The guest landing page advertised http:// service URLs (mixed-content on the
https origin) and the wrong packwiz subdomain:
- authUrl / authlibUrl: http -> https
- packwizUrl: http://packwiz. -> https://pack. (correct vhost)
- serverAddress: mc. -> apex (connect to ${BASE_DOMAIN}:25565)
- remove caCertUrl + the "trust the local CA" join step (airgap-only, /ca.crt
no longer exists) and its en/es/eu i18n strings + type.
Also fix the stale http BaseURL example in plan/03-drasl.md.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adopt the "Carved from stone" pixel design (landing/design/) as the apex
onboarding page, ported from its React/Babel-via-CDN prototype to static
Astro so it works on an offline LAN. Real modded-LAN content replaces the
prototype's fictional public-SMP copy.
- Vendor web fonts locally (tooling/fetch-fonts.sh -> public/fonts/) so the
page renders without the Google Fonts CDN at party time.
- Port the design system (main.css: mood/hero/bevels) and split markup into
Astro components (Creeper, PixelIcon, CopyChip, ServerListPanel).
- site.ts holds language-neutral config + theme knobs (mood/hero/headFont/
dust) that replace the design's in-browser TweaksPanel; LITERALS holds
never-translated product/in-game terms.
- i18n: English (/), Spanish (/es/), Euskera (/eu/) generated from one
[...lang].astro via getStaticPaths; copy lives in src/i18n/ui.ts. Nav has
an EN/ES/EU switcher; html lang + hreflang set per page.
- Status panel shows a static server-list row + honest stat tiles (no fake
live count). Copy + scroll-reveal are the only client JS.
Build emits to ../www (gitignored). Euskera strings pending a native review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>