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:
@@ -2,32 +2,92 @@
|
||||
|
||||
## Summary
|
||||
|
||||
Apex `ulicraft.local` serves a clean static page guiding guests through joining:
|
||||
Apex `ulicraft.local` serves a static page guiding guests through joining:
|
||||
download launcher → add account → import modpack → connect. Built with **Astro +
|
||||
TypeScript** in its own `./landing/` project; `npm run build` emits straight into
|
||||
`./www/`, which Caddy already serves at the apex domain. No runtime JS framework —
|
||||
output is plain HTML/CSS plus one tiny copy-to-clipboard script.
|
||||
TypeScript** in `./landing/`; `pnpm run build` emits straight into `./www/`,
|
||||
which Caddy/nginx serve at the apex. No runtime framework — output is plain
|
||||
HTML/CSS plus one tiny vanilla script (copy-to-clipboard + scroll reveal).
|
||||
|
||||
The visual is the **"Carved from stone"** pixel design ("Claude Design",
|
||||
`landing/design/`): dark overworld palette, MC-GUI bevel buttons, pixel type,
|
||||
creeper mark, server-list panel. That design was a React/Babel-via-CDN prototype
|
||||
for a *fictional public SMP*; it was **ported to static Astro** with the real
|
||||
modded-LAN content and offline-safe assets.
|
||||
|
||||
## Stack & wiring
|
||||
|
||||
- `landing/` — Astro project (own `package.json`, `tsconfig`).
|
||||
- `landing/` — Astro project (own `package.json`, `tsconfig`). pnpm only.
|
||||
- `astro.config.mjs` → `outDir: "../www"`. Build overwrites `www/`; `www/` is
|
||||
gitignored (generated artifact).
|
||||
- `BASE_DOMAIN` env read at build time in `src/data/site.ts`
|
||||
(`process.env.BASE_DOMAIN ?? "ulicraft.local"`). Bake before deploy:
|
||||
`BASE_DOMAIN=ulicraft.local pnpm run build`.
|
||||
- Logo: drop PNG at `landing/public/logo.png` → copied to `www/logo.png`,
|
||||
referenced as `/logo.png` (favicon + hero). `image-rendering: pixelated` keeps
|
||||
the stone 3D logo crisp.
|
||||
- Logo: wide wordmark from the design at `landing/public/logo.png` (hero + favicon).
|
||||
`image-rendering: pixelated` keeps it crisp.
|
||||
|
||||
## Content (src/data/site.ts is the single source)
|
||||
### Source layout
|
||||
```
|
||||
landing/
|
||||
├── design/ # "Claude Design" prototype (reference, not built)
|
||||
├── public/
|
||||
│ ├── logo.png # hero wordmark (from design/assets/ulicraft-logo.png)
|
||||
│ └── fonts/ # vendored woff2 + fonts.css (offline-safe)
|
||||
└── src/
|
||||
├── data/site.ts # single source: content + theme knobs
|
||||
├── styles/main.css # ported design system (mood/hero/bevels)
|
||||
├── components/ # Creeper, PixelIcon, CopyChip, ServerListPanel
|
||||
└── pages/index.astro # composition + copy/reveal script + dust
|
||||
```
|
||||
|
||||
- Hero: logo, name, server address `mc.${BASE_DOMAIN}:25565` (copy button).
|
||||
- Step 1: launcher downloads — 3 OS buttons → `/launcher/latest/<stable>`.
|
||||
- Step 2: add authlib-injector account, URL `http://auth.${BASE_DOMAIN}/authlib-injector`,
|
||||
register link to `http://auth.${BASE_DOMAIN}`.
|
||||
- Step 3: import packwiz `http://packwiz.${BASE_DOMAIN}/pack.toml`.
|
||||
- Step 4: connect to server address.
|
||||
## Fonts — vendored for offline LAN
|
||||
|
||||
The design pulled fonts from Google Fonts CDN; that breaks on offline LAN day.
|
||||
`tooling/fetch-fonts.sh` downloads the woff2 + a URL-rewritten `fonts.css` into
|
||||
`landing/public/fonts/`. `index.astro` links `/fonts/fonts.css`. Re-run the
|
||||
script only if the font set changes (keep families in sync with `main.css`
|
||||
`--font-*`): Pixelify Sans, Space Grotesk, Press Start 2P, Silkscreen, VT323.
|
||||
|
||||
## Theme config (replaces the design's in-browser TweaksPanel)
|
||||
|
||||
`site.ts` `theme` is baked at build — edit + rebuild to change:
|
||||
- `mood`: `grass` (default) | `nether` | `end`
|
||||
- `hero`: `centered` (default) | `split` | `spotlight`
|
||||
- `headFont`: `pixelify` (default) | `8bit` | `silkscreen`
|
||||
- `dust`: floating hero particles (CSS animation; respects reduced-motion)
|
||||
|
||||
`index.astro` sets `<html data-mood data-hero data-head>` + `--font-head` from these.
|
||||
|
||||
## Languages (i18n)
|
||||
|
||||
Three locales, static, build-time, offline-safe — **English** (default, `/`),
|
||||
**Spanish** (`/es/`), **Euskera** (`/eu/`).
|
||||
|
||||
- One template `src/pages/[...lang].astro` with `getStaticPaths` emits all three
|
||||
routes (`/`, `/es/`, `/eu/`). No runtime/JS routing.
|
||||
- Translatable copy lives in `src/i18n/ui.ts` (`ui[locale]`), keyed identically
|
||||
across locales. `site.ts` holds only language-neutral config (URLs, theme,
|
||||
launcher files, stat/feature *structure*).
|
||||
- Product / in-game literals never translated — `site.ts` `LITERALS`
|
||||
(`authlib-injector`, `Multiplayer`, `Add Server`). OS names + version too.
|
||||
- Sentences with links/kbd are split into parts (pre/post/link, pa/pb) so markup
|
||||
stays in the template, not the strings.
|
||||
- Nav has a pixel `EN · ES · EU` switcher (`.lang-switch`); active locale
|
||||
highlighted. `<html lang>` + `<link rel="alternate" hreflang>` set per page.
|
||||
- Adding a locale: extend the `Lang` union + `ui`/`LANG_*` maps in `ui.ts`, add a
|
||||
`getStaticPaths` entry. No template change.
|
||||
|
||||
## Content (real modded-LAN flow, all in site.ts)
|
||||
|
||||
- Hero: wordmark, eyebrow `Modded LAN · NeoForge 1.21.1`, tagline, sub, server
|
||||
address `mc.${BASE_DOMAIN}` (copy chip), "How to Join".
|
||||
- Status: static server-list panel (no fake live count — **option B**) + 4 honest
|
||||
stat tiles (Mods / NeoForge ver / Player slots / Backups).
|
||||
- Features ×4: kitchen-sink pack · self-hosted Drasl identity+skins · one-click
|
||||
packwiz · built-to-last (homelab + 6h backups).
|
||||
- How to Join ×4: **1** Fjord launcher (3 OS) → **2** authlib account
|
||||
(`auth.${BASE_DOMAIN}/authlib-injector`) + register link + CA-cert note →
|
||||
**3** packwiz import (`packwiz.${BASE_DOMAIN}/pack.toml`) → **4** connect.
|
||||
- Footer: Mojang trademark disclaimer.
|
||||
|
||||
## Launcher download links (Option A — stable symlinks)
|
||||
|
||||
@@ -38,16 +98,18 @@ Page links to fixed names so they survive launcher version bumps:
|
||||
|
||||
`tooling/fetch-launcher.sh` must create these as symlinks under
|
||||
`mirror/launcher/latest/` pointing at the real versioned assets. **Keep the names
|
||||
in sync** between `site.ts` and the script. Caddy mount
|
||||
`./mirror/launcher:/srv/www/launcher:ro` makes them resolve at `/launcher/latest/…`.
|
||||
in sync** between `site.ts` and the script. Mounted so they resolve at
|
||||
`/launcher/latest/…` (see nginx/Caddy ingress).
|
||||
|
||||
## Tasks
|
||||
|
||||
- [ ] User: place logo at `landing/public/logo.png`
|
||||
- [ ] `cd landing && pnpm install`
|
||||
- [ ] `BASE_DOMAIN=ulicraft.local pnpm run build` → verify `www/index.html` + `www/logo.png`
|
||||
- [ ] Extend `fetch-launcher.sh`: after download, symlink stable names → versioned files
|
||||
(resolve which asset = win setup / mac dmg / linux AppImage)
|
||||
- [ ] Confirm Caddy serves apex from `./www` and `/launcher/latest/*` from mirror
|
||||
- [ ] Optional: pin launcher tag instead of `latest` for party day
|
||||
- [ ] Optional: add a "what's in the pack" section once mod list firms up
|
||||
- [x] Vendor fonts (`tooling/fetch-fonts.sh`) → `public/fonts/`
|
||||
- [x] Port design → static Astro (components + main.css + index.astro)
|
||||
- [x] Real content in `site.ts`; theme knobs replace TweaksPanel
|
||||
- [x] i18n: en/es/eu via `[...lang].astro` + `i18n/ui.ts`; nav language switcher
|
||||
- [x] `BASE_DOMAIN=ulicraft.local pnpm run build` → verified `www/` output + screenshot
|
||||
- [ ] Extend `fetch-launcher.sh`: symlink stable names → versioned files
|
||||
- [ ] Confirm ingress serves apex from `./www` and `/launcher/latest/*` from mirror
|
||||
- [ ] Optional: try `mood: nether` / `hero: split` for party day
|
||||
- [ ] Optional: wire real player count (option C) via mc-monitor JSON if wanted
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user