feat(landing): pixel design ported to static Astro + en/es/eu i18n

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>
This commit is contained in:
2026-06-08 18:18:36 +02:00
parent 5cec2993d7
commit 3d52951355
60 changed files with 3388 additions and 228 deletions

340
landing/src/i18n/ui.ts Normal file
View File

@@ -0,0 +1,340 @@
// Translatable UI copy for the landing page. Structure is identical across
// locales; the page (src/pages/[...lang].astro) renders against it.
//
// Conventions:
// - "{name}" in step1 is replaced with the launcher name at render time.
// - Sentences containing links/kbd/literals are split into parts (a/b/pre/
// post/link) so the markup stays in the template, not in the strings.
// - Product / in-game literals (authlib-injector, Multiplayer, Add Server)
// live in site.ts LITERALS and are never translated.
export type Lang = "en" | "es" | "eu";
export const LANGS: Lang[] = ["en", "es", "eu"];
export const LANG_LABEL: Record<Lang, string> = { en: "EN", es: "ES", eu: "EU" };
// URL path per locale (en is default, served at root).
export const LANG_PATH: Record<Lang, string> = { en: "/", es: "/es/", eu: "/eu/" };
export interface UI {
htmlLang: string;
copied: string; // transient copy-button feedback
nav: { status: string; features: string; join: string; play: string };
hero: {
eyebrow: string; // "Modded LAN · NeoForge" — version appended at render
tagline: string;
sub: string;
copyIp: string;
howToJoin: string;
metaModpack: string;
metaLan: string;
};
status: {
eyebrow: string;
title: string;
lead: string;
modded: string;
motd: string;
upTo: string;
};
statLabels: [string, string, string, string];
features: {
eyebrow: string;
title: string;
lead: string;
items: { h: string; p: string }[];
};
join: {
eyebrow: string;
title: string;
lead: string;
s1: { kicker: string; h: string; p: string };
s2: {
kicker: string;
h: string;
pa: string; // before the authlib-injector literal
pb: string; // after it
copy: string;
registerPre: string;
caPre: string;
caLink: string;
caPost: string;
};
s3: { kicker: string; h: string; p: string };
s4: {
kicker: string;
h: string;
pa: string; // before the Multiplayer/Add Server kbds
pb: string; // after them
copy: string;
};
};
footer: { join: string; disc: string };
}
export const ui: Record<Lang, UI> = {
en: {
htmlLang: "en",
copied: "Copied!",
nav: { status: "Status", features: "Features", join: "How to Join", play: "Play Now" },
hero: {
eyebrow: "Modded LAN · NeoForge",
tagline: "Kitchen-sink survival, built to outlast the weekend.",
sub:
"A self-hosted modded server for the crew — a curated tech + magic + " +
"exploration pack, your own skins, one-click setup. Grab the address, " +
"import the pack, dig in.",
copyIp: "Copy IP",
howToJoin: "How to Join",
metaModpack: "NeoForge modpack",
metaLan: "LAN-only",
},
status: {
eyebrow: "Server",
title: "This is what you'll see.",
lead: "Exactly the entry that shows up in your multiplayer list.",
modded: "Modded",
motd: "NeoForge modpack · Simple Voice Chat · LAN-only",
upTo: "up to",
},
statLabels: ["Mods", "NeoForge", "Player slots", "World backups"],
features: {
eyebrow: "What makes it Ulicraft",
title: "Built for the crew.",
lead:
"Self-hosted, curated, and persistent — a modded server that respects " +
"your time and outlives the LAN.",
items: [
{
h: "Kitchen-sink pack",
p: "~50100 hand-picked mods — tech, magic, exploration and QoL. NeoForge 1.21.1, curated, no bloat.",
},
{
h: "Your identity, self-hosted",
p: "Drasl runs accounts and skins on the LAN. No Mojang login needed — your skin and cape just work.",
},
{
h: "One-click setup",
p: "packwiz installs and updates the whole modpack inside your launcher, so everyone stays in sync.",
},
{
h: "Built to last",
p: "Not a weekend throwaway — it runs on the homelab with 6-hour world backups. Your base survives.",
},
],
},
join: {
eyebrow: "How to Join · 4 Steps",
title: "From zero to spawning in.",
lead: "One-time setup. After this, the launcher keeps you in sync.",
s1: {
kicker: "Launcher",
h: "Download {name}",
p: "Grab {name} for your system — a Prism-based launcher with authlib-injector support built in.",
},
s2: {
kicker: "Account",
h: "Add your account",
pa: "In the launcher, add an",
pb: "account using this URL, then log in with your Ulicraft credentials.",
copy: "Copy",
registerPre: "Need credentials? Register at",
caPre: "Offline party? Download and trust the",
caLink: "local CA certificate",
caPost: "so the game-file mirror works over HTTPS.",
},
s3: {
kicker: "Modpack",
h: "Import the modpack",
p: "Add a new instance from this packwiz URL — it installs and updates the whole pack.",
},
s4: {
kicker: "Connect",
h: "Join the server",
pa: "Launch the instance, open",
pb: ", paste the address, and join.",
copy: "Copy IP",
},
},
footer: {
join: "How to Join",
disc: "Not affiliated with Mojang or Microsoft. Minecraft is a trademark of Mojang AB.",
},
},
es: {
htmlLang: "es",
copied: "¡Copiado!",
nav: { status: "Estado", features: "Características", join: "Cómo entrar", play: "Jugar ahora" },
hero: {
eyebrow: "LAN con mods · NeoForge",
tagline: "Supervivencia todo incluido, para durar más que el finde.",
sub:
"Un servidor con mods autoalojado para la cuadrilla: un pack curado de " +
"tecnología, magia y exploración, tus propias skins y configuración en un " +
"clic. Copia la dirección, importa el pack y a cavar.",
copyIp: "Copiar IP",
howToJoin: "Cómo entrar",
metaModpack: "Pack NeoForge",
metaLan: "Solo LAN",
},
status: {
eyebrow: "Servidor",
title: "Esto es lo que verás.",
lead: "La misma entrada que aparece en tu lista de multijugador.",
modded: "Con mods",
motd: "Pack NeoForge · Simple Voice Chat · Solo LAN",
upTo: "hasta",
},
statLabels: ["Mods", "NeoForge", "Plazas", "Copias del mundo"],
features: {
eyebrow: "Qué hace especial a Ulicraft",
title: "Hecho para la cuadrilla.",
lead:
"Autoalojado, curado y persistente: un servidor con mods que respeta tu " +
"tiempo y sobrevive a la LAN.",
items: [
{
h: "Pack todo incluido",
p: "~50100 mods elegidos a mano: tecnología, magia, exploración y QoL. NeoForge 1.21.1, curado y sin relleno.",
},
{
h: "Tu identidad, autoalojada",
p: "Drasl gestiona cuentas y skins en la LAN. Sin login de Mojang: tu skin y tu capa funcionan sin más.",
},
{
h: "Configuración en un clic",
p: "packwiz instala y actualiza todo el modpack dentro de tu launcher, así todos vais sincronizados.",
},
{
h: "Hecho para durar",
p: "No es de usar y tirar: corre en el homelab con copias del mundo cada 6 horas. Tu base sobrevive.",
},
],
},
join: {
eyebrow: "Cómo entrar · 4 pasos",
title: "De cero a aparecer en el mundo.",
lead: "Configuración única. Después, el launcher te mantiene sincronizado.",
s1: {
kicker: "Launcher",
h: "Descarga {name}",
p: "Coge {name} para tu sistema: un launcher basado en Prism con soporte authlib-injector integrado.",
},
s2: {
kicker: "Cuenta",
h: "Añade tu cuenta",
pa: "En el launcher, añade una cuenta",
pb: "con esta URL y luego inicia sesión con tus credenciales de Ulicraft.",
copy: "Copiar",
registerPre: "¿Sin credenciales? Regístrate en",
caPre: "¿Fiesta sin internet? Descarga y confía en el",
caLink: "certificado CA local",
caPost: "para que el mirror de archivos funcione por HTTPS.",
},
s3: {
kicker: "Modpack",
h: "Importa el modpack",
p: "Añade una instancia nueva desde esta URL de packwiz: instala y actualiza todo el pack.",
},
s4: {
kicker: "Conectar",
h: "Entra al servidor",
pa: "Lanza la instancia, abre",
pb: ", pega la dirección y entra.",
copy: "Copiar IP",
},
},
footer: {
join: "Cómo entrar",
disc: "No afiliado a Mojang ni Microsoft. Minecraft es una marca de Mojang AB.",
},
},
eu: {
htmlLang: "eu",
copied: "Kopiatuta!",
nav: { status: "Egoera", features: "Ezaugarriak", join: "Nola sartu", play: "Jokatu orain" },
hero: {
eyebrow: "Mod-dun LANa · NeoForge",
tagline: "Mod ugariko biziraupena, irauteko egina.",
sub:
"Koadrilarentzako mod-dun zerbitzari auto-ostatatua: teknologia, magia eta " +
"esplorazio pack zaindua, zure azalak eta konfigurazioa klik bakarrean. " +
"Hartu helbidea, inportatu packa eta hasi zulatzen.",
copyIp: "Kopiatu IPa",
howToJoin: "Nola sartu",
metaModpack: "NeoForge packa",
metaLan: "LAN soilik",
},
status: {
eyebrow: "Zerbitzaria",
title: "Hau ikusiko duzu.",
lead: "Zure multijokalari-zerrendan agertzen den sarrera bera.",
modded: "Mod-duna",
motd: "NeoForge packa · Simple Voice Chat · LAN soilik",
upTo: "gehienez",
},
statLabels: ["Modak", "NeoForge", "Plazak", "Munduaren babeskopiak"],
features: {
eyebrow: "Zerk egiten du Ulicraft berezi",
title: "Koadrilarentzat eginda.",
lead:
"Auto-ostatatua, zaindua eta iraunkorra: zure denbora errespetatzen duen " +
"eta LANa gainditzen duen mod-dun zerbitzaria.",
items: [
{
h: "Pack osoa",
p: "Eskuz aukeratutako ~50100 mod: teknologia, magia, esplorazioa eta QoL. NeoForge 1.21.1, zaindua eta betegarririk gabe.",
},
{
h: "Zure nortasuna, auto-ostatatua",
p: "Draslek kontuak eta azalak LANean kudeatzen ditu. Mojang loginik gabe: zure azalak eta kapak besterik gabe dabiltza.",
},
{
h: "Konfigurazioa klik batean",
p: "packwiz-ek modpack osoa instalatu eta eguneratzen du zure launcherrean, denok sinkronizatuta egoteko.",
},
{
h: "Irauteko eginda",
p: "Ez da behin erabili eta botatzekoa: homelab-ean dabil, munduaren babeskopiak 6 orduro. Zure basea bizirik.",
},
],
},
join: {
eyebrow: "Nola sartu · 4 urrats",
title: "Zerotik mundura agertzera.",
lead: "Behin bakarrik konfiguratu. Gero, launcherrak sinkronizatuta mantenduko zaitu.",
s1: {
kicker: "Launcherra",
h: "Deskargatu {name}",
p: "Hartu {name} zure sistemarako: Prism-en oinarritutako launcherra, authlib-injector euskarriarekin.",
},
s2: {
kicker: "Kontua",
h: "Gehitu zure kontua",
pa: "Launcherrean, gehitu",
pb: "kontu bat URL honekin, eta gero hasi saioa zure Ulicraft kredentzialekin.",
copy: "Kopiatu",
registerPre: "Kredentzialik ez? Erregistratu hemen:",
caPre: "Internetik gabeko festa? Deskargatu eta fidatu",
caLink: "tokiko CA ziurtagiriaz",
caPost: "fitxategi-mirrorrak HTTPS bidez ibil dadin.",
},
s3: {
kicker: "Modpacka",
h: "Inportatu modpacka",
p: "Gehitu instantzia berri bat packwiz URL honetatik: pack osoa instalatu eta eguneratzen du.",
},
s4: {
kicker: "Konektatu",
h: "Sartu zerbitzarira",
pa: "Abiarazi instantzia, ireki",
pb: ", itsatsi helbidea eta sartu.",
copy: "Kopiatu IPa",
},
},
footer: {
join: "Nola sartu",
disc: "Ez dago Mojang edo Microsoft-ekin lotuta. Minecraft Mojang AB-ren marka da.",
},
},
};