diff --git a/PLAN.md b/PLAN.md
index cddcc65..5ae207e 100644
--- a/PLAN.md
+++ b/PLAN.md
@@ -284,3 +284,17 @@ Abgabe: **9. Dezember 2026, 03:00 MEZ**. Eingereicht wird in „Best Daily Game
Aufnahmen werden vorher nach VP9/WebM umgewandelt.
- Reddit selbst (Feed, Kommentar im Thread, Flair) nimmt der Besitzer mit seinem Konto auf (Reddit blockt
Automatisierung); optional als `dist/trailer/input/feed.*` / `comment.*`.
+
+### 2026-11-13 – Realm im Vollbild (Bug vom Besitzer)
+
+- **Bug:** Am Handy öffnete „🎨 Realm“ das Fenster im Inline-Post (512 px hoch). Die Liste ist höher, „Done“ lag
+ außerhalb, und scrollen darf ein Inline-Post nicht (Devvit-Regel „Scrolling within inline webviews is prohibited“,
+ Scroll-Falle im Feed) → man saß fest.
+- **Lösung:** eigener Einstiegspunkt `realm` (`public/realm.html`, `src/client/realm-page.ts`), geöffnet mit
+ `requestExpandedMode(ev, 'realm', {title: 'Your realm'})`; „Done“ ruft `exitExpandedMode`. Der Knopf klebt unten
+ (`position: sticky`), damit er auch bei langer Liste sichtbar bleibt. Der Startbildschirm lädt beim `focus`-Ereignis
+ (Rückkehr aus dem Vollbild, laut Doku der Ersatz für `addWebViewModeListener`) Tag und Aussehen neu – damit zeigt er
+ nach dem Spielen auch gleich das eigene Ergebnis.
+- Credits-Fenster im Post geprüft: passt auch bei 320 px Breite (Knopf endet bei 413 von 512 px).
+- Pixelify-Ligatur „fi“ (sieht aus wie „A“) jetzt für die ganze App aus (`font-variant-ligatures: none`).
+- **Fallstrick:** `devvit.json` geändert → laufenden Playtest stoppen und neu starten.
diff --git a/devvit.json b/devvit.json
index a6e56ee..c895b15 100644
--- a/devvit.json
+++ b/devvit.json
@@ -10,6 +10,9 @@
},
"game": {
"entry": "game.html"
+ },
+ "realm": {
+ "entry": "realm.html"
}
}
},
diff --git a/package.json b/package.json
index de42295..44d87f9 100644
--- a/package.json
+++ b/package.json
@@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"build": "npm run build:client -- --metafile=dist/client.meta.json --minify && npm run build:server -- --metafile=dist/server.meta.json --minify",
- "build:client": "esbuild --bundle --log-level=warning --sourcemap=linked --target=es2023 --format=esm --outdir=public --platform=browser --define:import.meta.env.MODE='\"reddit\"' --define:import.meta.env.BASE_URL='\"/\"' --define:__API_ORIGIN__='\"\"' --loader:.woff2=file --loader:.woff=file --asset-names=fonts/[name]-[hash] src/client/splash.ts src/client/game.ts",
+ "build:client": "esbuild --bundle --log-level=warning --sourcemap=linked --target=es2023 --format=esm --outdir=public --platform=browser --define:import.meta.env.MODE='\"reddit\"' --define:import.meta.env.BASE_URL='\"/\"' --define:__API_ORIGIN__='\"\"' --loader:.woff2=file --loader:.woff=file --asset-names=fonts/[name]-[hash] src/client/splash.ts src/client/game.ts src/client/realm-page.ts",
"build:server": "esbuild --bundle --log-level=warning --sourcemap=linked --target=es2023 --format=cjs --outdir=dist/server --platform=node src/server/index.ts",
"clean": "rm -rf dist/ public/*.js* public/*.css* public/fonts/",
"format": "npm run lint -- --fix",
diff --git a/public/realm.html b/public/realm.html
new file mode 100644
index 0000000..1d70a46
--- /dev/null
+++ b/public/realm.html
@@ -0,0 +1,14 @@
+
+
+
+
+
+ Ninelands
+
+
+
+
+
+
+
+
diff --git a/scripts/capture/trailer.mjs b/scripts/capture/trailer.mjs
index a541ab8..49f64f0 100644
--- a/scripts/capture/trailer.mjs
+++ b/scripts/capture/trailer.mjs
@@ -349,17 +349,24 @@ async function scenes(page, o) {
'Streaks and stars unlock boards, peoples and banners.',
)
await wait(900)
- const s2 = frameOf('splash.html')
- await tap(s2.locator('.realm-btn'), 300)
- await wait(700)
- await tap(s2.locator('.realm-item', {hasText: 'Winter'}).first(), 400)
+ // Realm öffnet im Vollbild (requestExpandedMode gibt es hier nicht → nur antippen, Bühne wechselt)
+ await tap(frameOf('splash.html').locator('.realm-btn'), 300, false)
+ await wait(300)
+ await stage('finger', null)
+ await stage('show', 'game', '/realm.html')
+ const r = frameOf('realm.html')
+ await r.waitForSelector('.realm-item')
+ await wait(600)
+ await tap(r.locator('.realm-item', {hasText: 'Winter'}).first(), 400)
await wait(900)
await stage('finger', null)
await o.snap('05-realm')
await wait(800)
- await tap(s2.locator('.overlay button.primary', {hasText: 'Done'}), 300)
+ await tap(r.locator('.overlay button.primary', {hasText: 'Done'}), 300, false)
+ await wait(300)
await stage('finger', null)
- await wait(400)
+ await stage('show', 'post', '/splash.html')
+ await wait(700)
await stage(
'caption',
diff --git a/src/client/realm-page.ts b/src/client/realm-page.ts
new file mode 100644
index 0000000..c085b19
--- /dev/null
+++ b/src/client/realm-page.ts
@@ -0,0 +1,35 @@
+// „🎨 Realm“ im Vollbild (Einstiegspunkt „realm“): Aussehen wählen, „Done“ führt zurück in den Post.
+import './style.css'
+import {exitExpandedMode} from '@devvit/web/client'
+import {dailyMap} from '../shared/daily.ts'
+import {fetchDay} from './api.ts'
+import {byId, h} from './dom.ts'
+import {applyLook, openRealm} from './realm.ts'
+
+const app = byId('app')
+
+async function main(): Promise {
+ app.replaceChildren(h('div.loading', 'Loading…'))
+ try {
+ const day = await fetchDay()
+ app.replaceChildren()
+ applyLook(day.look)
+ openRealm({
+ look: day.look,
+ progress: {
+ bestStreak: day.stats?.bestStreak ?? 0,
+ totalStars: day.stats?.totalStars ?? 0,
+ },
+ day: dailyMap(new Date()).day,
+ loggedIn: day.loggedIn,
+ onChange: look => applyLook(look),
+ onClose: ev => exitExpandedMode(ev),
+ })
+ } catch (err) {
+ app.replaceChildren(
+ h('div.error', `Could not load your realm. ${(err as Error).message}`),
+ )
+ }
+}
+
+void main()
diff --git a/src/client/realm.ts b/src/client/realm.ts
index 5a0bcf0..66a0b6d 100644
--- a/src/client/realm.ts
+++ b/src/client/realm.ts
@@ -75,6 +75,8 @@ export function openRealm(opts: {
day: string
loggedIn: boolean
onChange: (look: Look) => void
+ /** Statt nur das Fenster zu schließen (Vollbild-Seite: zurück in den Post) */
+ onClose?: (ev: MouseEvent) => void
}): void {
let look = opts.look
const body = h('div.realm-rows')
@@ -94,7 +96,9 @@ export function openRealm(opts: {
h('div.row.end', close),
),
)
- close.addEventListener('click', () => overlay.remove())
+ close.addEventListener('click', ev =>
+ opts.onClose ? opts.onClose(ev) : overlay.remove(),
+ )
const row = (
title: string,
diff --git a/src/client/splash.ts b/src/client/splash.ts
index 71dad5c..35350ad 100644
--- a/src/client/splash.ts
+++ b/src/client/splash.ts
@@ -9,7 +9,7 @@ import {dailyBoard, dailyMap, dayLabel} from '../shared/daily.ts'
import {fetchDay} from './api.ts'
import {byId, h} from './dom.ts'
import {appReady} from './journeys.ts'
-import {applyLook, openRealm} from './realm.ts'
+import {applyLook} from './realm.ts'
import {leaderTable} from './result.ts'
import {lawName, starsLine} from './texts.ts'
@@ -28,6 +28,12 @@ async function main(): Promise {
}
render(day)
appReady()
+ // Zurück aus dem Vollbild (Spiel oder Realm): Ergebnis und Aussehen neu holen
+ addEventListener('focus', () => {
+ fetchDay()
+ .then(render)
+ .catch(() => {})
+ })
}
function render(day: GetDayRsp): void {
@@ -38,21 +44,10 @@ function render(day: GetDayRsp): void {
const realm = h('button.icon.realm-btn', '🎨 Realm')
realm.title = 'Customise your realm'
- realm.addEventListener('click', () =>
- openRealm({
- look: day.look,
- progress: {
- bestStreak: day.stats?.bestStreak ?? 0,
- totalStars: day.stats?.totalStars ?? 0,
- },
- day: dailyMap(new Date()).day,
- loggedIn: day.loggedIn,
- onChange: look => {
- day.look = look
- applyLook(look)
- renderMiniBoard(mini, dailyBoard(map))
- },
- }),
+ // Im Vollbild: der Inline-Post ist nur 512 px hoch und darf nicht scrollen (Devvit-Regel) – sonst wäre
+ // „Done“ am Handy unerreichbar
+ realm.addEventListener('click', ev =>
+ requestExpandedMode(ev, 'realm', {title: 'Your realm'}),
)
const play = h('button.primary', day.mine ? 'Play again' : 'Play')
diff --git a/src/client/style.css b/src/client/style.css
index 0ca145e..1d1e480 100644
--- a/src/client/style.css
+++ b/src/client/style.css
@@ -43,6 +43,8 @@ body {
body {
background-color: var(--px-grass-dark);
+ /* Pixelify verbindet „fi“ sonst zu einem Zeichen, das wie „A“ aussieht */
+ font-variant-ligatures: none;
/* feines Schachbrett wie Grasnarbe */
background-image: conic-gradient(
rgba(0, 0, 0, 0.08) 25%,
@@ -219,6 +221,16 @@ button.icon {
}
/* ---------- Realm-Auswahl ---------- */
+/* „Done“ bleibt unten sichtbar, auch wenn die Liste scrollt (Vollbild am Handy) */
+.realm > .row.end {
+ position: sticky;
+ bottom: -1rem;
+ margin: 0 -1rem -1rem;
+ padding: 0.6rem 1rem;
+ background: var(--px-wood);
+ border-top: 2px solid var(--px-ink);
+}
+
.realm h3 {
margin: 0 0 0.25rem;
font-family: var(--font-pixel);