Compare commits

...
4 Commits
Author SHA1 Message Date
Gitea Actions 4c36c5e421 Release 0.1.22 [auto-version-bump] 2026-10-14 23:00:16 +02:00
Ein Anderssono 370af29c47 Clarify text and dialogue based accessibility
Build and publish frontend / publish (push) Successful in 50s
2026-10-14 22:59:49 +02:00
Gitea Actions 1d60387a9b Release 0.1.21 [auto-version-bump] 2026-10-14 22:49:40 +02:00
Ein Anderssono 4502e2406d Add multisensory accessible place details
Build and publish frontend / publish (push) Successful in 41s
2026-10-14 22:49:18 +02:00
5 changed files with 37 additions and 4 deletions
+2
View File
@@ -4,6 +4,8 @@ This repository contains the static Swedish web client for the AI-driven life si
Players provide a character biography, not a world description. The client asks the backend to create a biography-based starting place. It does not preview a person the player may meet; encounters belong to later world exploration. Players provide a character biography, not a world description. The client asks the backend to create a biography-based starting place. It does not preview a person the player may meet; encounters belong to later world exploration.
The game is text- and dialogue-based and uses no images. Place descriptions include sound, smell, air/temperature, touch/surface, and spatial-orientation cues. Visible details may also be described in words, but are never required to understand the scene or play.
The browser and API stay on the same public origin, `https://ai-spel.k3s.k0.nu`. The ingress routes `/` to this frontend service and routes `/api`, `/version`, and `/health` to the Rust service. That keeps the current server-side session cookie same-origin and avoids browser CORS configuration. The browser and API stay on the same public origin, `https://ai-spel.k3s.k0.nu`. The ingress routes `/` to this frontend service and routes `/api`, `/version`, and `/health` to the Rust service. That keeps the current server-side session cookie same-origin and avoids browser CORS configuration.
## Release flow ## Release flow
+1 -1
View File
@@ -1 +1 @@
0.1.20 0.1.22
+2 -2
View File
@@ -2,5 +2,5 @@ apiVersion: v2
name: ai-spel-frontend name: ai-spel-frontend
description: Static web frontend for the Swedish life simulator description: Static web frontend for the Swedish life simulator
type: application type: application
version: 0.1.20 version: 0.1.22
appVersion: "0.1.20" appVersion: "0.1.22"
+26 -1
View File
@@ -16,6 +16,9 @@
button { justify-self: start; cursor: pointer; } button { justify-self: start; cursor: pointer; }
#status { min-height: 1.5em; } #status { min-height: 1.5em; }
.card { border: 1px solid; border-radius: .5rem; padding: 1rem; margin-block: 1rem; } .card { border: 1px solid; border-radius: .5rem; padding: 1rem; margin-block: 1rem; }
dl { display: grid; grid-template-columns: minmax(8rem, 12rem) 1fr; gap: .35rem 1rem; }
dt { font-weight: 700; }
dd { margin: 0; }
.row { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; } .row { display: flex; flex-wrap: wrap; gap: .75rem; align-items: center; }
.row button { margin-block: .4rem; } .row button { margin-block: .4rem; }
#transcript { min-height: 5rem; max-height: 28rem; overflow: auto; } #transcript { min-height: 5rem; max-height: 28rem; overflow: auto; }
@@ -26,6 +29,7 @@
<body> <body>
<main> <main>
<h1>En värld du formar</h1> <h1>En värld du formar</h1>
<p>Spelet är text- och dialogbaserat och använder inga bilder. Miljöer beskrivs med ljud, dofter, temperatur, beröring och orientering, inte bara med synintryck.</p>
<p>Skapa en vuxen person och forma en egen vardag. AI-förslag sparas inte förrän du har granskat och godkänt dem.</p> <p>Skapa en vuxen person och forma en egen vardag. AI-förslag sparas inte förrän du har granskat och godkänt dem.</p>
<p id="status" role="status" aria-live="polite"></p> <p id="status" role="status" aria-live="polite"></p>
<section id="auth" aria-labelledby="auth-heading"> <section id="auth" aria-labelledby="auth-heading">
@@ -52,9 +56,18 @@
<button id="start-world-button" type="button">Börja spela</button> <button id="start-world-button" type="button">Börja spela</button>
</section> </section>
<section id="game" hidden> <section id="game" hidden>
<div class="row"><h2 id="world-heading"></h2><button id="logout" type="button">Logga ut</button></div> <div class="row"><h2 id="world-heading" tabindex="-1"></h2><button id="logout" type="button">Logga ut</button></div>
<section class="card" aria-labelledby="place-heading"> <section class="card" aria-labelledby="place-heading">
<h3 id="place-heading"></h3><p id="place-description"></p> <h3 id="place-heading"></h3><p id="place-description"></p>
<h4>Platsens sinnesintryck</h4>
<dl>
<dt>Utseende beskrivet i ord</dt><dd id="sense-visual"></dd>
<dt>Ljud</dt><dd id="sense-sound"></dd>
<dt>Dofter</dt><dd id="sense-smell"></dd>
<dt>Luft och temperatur</dt><dd id="sense-air"></dd>
<dt>Beröring och ytor</dt><dd id="sense-touch"></dd>
<dt>Orientering i rummet</dt><dd id="sense-orientation"></dd>
</dl>
<p id="place-status" role="status"></p> <p id="place-status" role="status"></p>
<h3 id="npc-heading"></h3><p id="npc-description"></p> <h3 id="npc-heading"></h3><p id="npc-description"></p>
<h3 id="player-heading"></h3><p id="player-biography"></p> <h3 id="player-heading"></h3><p id="player-biography"></p>
@@ -126,8 +139,20 @@
auth.hidden = true; characterSection.hidden = true; game.hidden = false; auth.hidden = true; characterSection.hidden = true; game.hidden = false;
worldSetup.hidden = true; worldSetup.hidden = true;
document.querySelector('#world-heading').textContent = world.name; document.querySelector('#world-heading').textContent = world.name;
document.querySelector('#world-heading').focus();
document.querySelector('#place-heading').textContent = world.location.name; document.querySelector('#place-heading').textContent = world.location.name;
document.querySelector('#place-description').textContent = world.location.description; document.querySelector('#place-description').textContent = world.location.description;
const senses = world.location.senses ?? {};
for (const [id, key] of [
['sense-visual', 'visual'],
['sense-sound', 'sound'],
['sense-smell', 'smell'],
['sense-air', 'air_and_temperature'],
['sense-touch', 'touch_and_surfaces'],
['sense-orientation', 'spatial_orientation'],
]) {
document.querySelector(`#${id}`).textContent = senses[key] || 'Inget särskilt intryck beskrivet.';
}
const conversation = document.querySelector('#conversation-card'); const conversation = document.querySelector('#conversation-card');
if (world.npc) { if (world.npc) {
document.querySelector('#npc-heading').textContent = world.npc.name; document.querySelector('#npc-heading').textContent = world.npc.name;
+6
View File
@@ -4,11 +4,17 @@ set -euo pipefail
test -s index.html test -s index.html
grep -q '<html lang="sv">' index.html grep -q '<html lang="sv">' index.html
grep -q '<h1>En värld du formar</h1>' index.html grep -q '<h1>En värld du formar</h1>' index.html
grep -q 'text- och dialogbaserat och använder inga bilder' index.html
grep -q 'id="frontend-version">__FRONTEND_VERSION__' index.html grep -q 'id="frontend-version">__FRONTEND_VERSION__' index.html
grep -q "request('/version')" index.html grep -q "request('/version')" index.html
grep -q 'id="api-version"' index.html grep -q 'id="api-version"' index.html
grep -Fq "credentials: 'same-origin'" index.html grep -Fq "credentials: 'same-origin'" index.html
grep -q 'Köp på platsen' index.html grep -q 'Köp på platsen' index.html
grep -q 'Platsens sinnesintryck' index.html
grep -q 'Orientering i rummet' index.html
grep -q "'sense-sound', 'sound'" index.html
grep -q 'id="world-heading" tabindex="-1"' index.html
grep -q "document.querySelector('#world-heading').focus()" index.html
grep -q "request('/api/purchases'" index.html grep -q "request('/api/purchases'" index.html
grep -q "request('/api/world/start'" index.html grep -q "request('/api/world/start'" index.html
if grep -Eq 'world/draft|npc_name|Person du kan möta|Beskriv vad du vill börja med' index.html; then if grep -Eq 'world/draft|npc_name|Person du kan möta|Beskriv vad du vill börja med' index.html; then