-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathindex.html
More file actions
318 lines (300 loc) · 13.4 KB
/
Copy pathindex.html
File metadata and controls
318 lines (300 loc) · 13.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
/>
<meta name="theme-color" content="#0b0b12" />
<meta
name="description"
content="Kettermean — a liminal first-person dream walker with LLM-generated rooms."
/>
<link rel="icon" href="./favicon.svg" type="image/svg+xml" />
<title>Kettermean</title>
<link rel="stylesheet" href="/src/styles/main.css" />
</head>
<body>
<div id="app">
<canvas id="game-canvas" tabindex="0" aria-label="Dream world"></canvas>
<div id="hud" class="hidden" aria-live="polite">
<div id="hud-theme"></div>
<div id="hud-seed"></div>
<div id="hud-ai-status">AI · preparing direction</div>
<div id="hud-hint">The room waits.</div>
<div id="hud-rule" class="hidden"></div>
<div id="hud-actions">
<div id="hud-action" class="hud-action"><kbd>R</kbd><span id="hud-next-state">Next dream · anytime</span></div>
<div id="hud-flashlight" class="hud-action">
<kbd>F</kbd><span id="hud-flashlight-state">Flashlight · off</span>
</div>
</div>
</div>
<div id="hud-npc-line" class="hidden" role="status" aria-live="polite" aria-atomic="true"></div>
<div id="fade-overlay" aria-hidden="true"></div>
<section id="ai-recovery" class="ai-recovery hidden" role="alert" aria-labelledby="ai-recovery-title">
<div>
<strong id="ai-recovery-title">The next dream did not form.</strong>
<span id="ai-recovery-message">Retry the AI or explicitly use one procedural room.</span>
</div>
<div class="ai-recovery-actions">
<button id="retry-ai-btn" type="button"><kbd>R</kbd> Retry AI</button>
<button id="procedural-next-btn" type="button"><kbd>O</kbd> Use procedural room</button>
</div>
</section>
<div id="touch-controls" class="hidden" aria-hidden="true">
<button id="touch-pause" class="touch-action touch-pause" type="button" aria-label="Pause game">Ⅱ</button>
<div id="stick-move" class="stick-zone">
<div class="stick-base"><div class="stick-knob"></div></div>
</div>
<div id="stick-look" class="stick-zone">
<div class="stick-base"><div class="stick-knob"></div></div>
</div>
<div class="touch-actions" aria-label="Movement actions">
<button id="touch-next" class="touch-action next" type="button">Next</button>
<button id="touch-flashlight" class="touch-action flashlight" type="button" aria-pressed="false">Light</button>
<button id="touch-sprint" class="touch-action" type="button">Sprint</button>
<button id="touch-jump" class="touch-action primary" type="button">Jump</button>
</div>
</div>
<div id="menu" class="menu-shell">
<img
class="menu-backdrop"
src="./kettermean-menu-bg.png"
alt=""
aria-hidden="true"
/>
<div class="menu-vignette" aria-hidden="true"></div>
<header class="menu-brand">
<p class="eyebrow">A procedural threshold</p>
<h1>Kettermean</h1>
<span class="brand-rule" aria-hidden="true"></span>
<p class="tagline">
Walk through liminal rooms.<br />
Leave with <strong>R</strong> when you are ready.<br />
Let the dream drift.
</p>
<button id="start-btn" type="button" class="enter-button">
<span aria-hidden="true">→</span>
<span>Enter dream</span>
</button>
</header>
<aside class="settings-rail" aria-label="Dream settings">
<div class="rail-scroll">
<section class="rail-section rail-section-first">
<h2>Dream mode</h2>
<label class="field field-inline">
<span>Mode</span>
<select id="mode-select">
<option value="random" selected>Fresh random dream</option>
<option value="seeded">Seeded continuum</option>
</select>
</label>
<label class="field field-inline" id="seed-field">
<span>Seed</span>
<input
id="seed-input"
type="text"
placeholder="e.g. yellow-hallway-07"
autocomplete="off"
/>
</label>
<p class="help dream-mode-help">
Random mode starts elsewhere every time. A seed recreates a related continuum.
</p>
</section>
<details id="ai-settings" class="ai-disclosure rail-section">
<summary>
<span class="ai-summary-copy">
<span class="section-title">AI direction</span>
<strong id="ai-provider-status">Browser model</strong>
<span id="ai-model-status">SmolLM2 360M</span>
</span>
<span class="ai-settings-label">
<span>AI settings</span><span class="disclosure-arrow" aria-hidden="true">›</span>
</span>
</summary>
<div class="ai-settings-body">
<p class="help ai-intro">
WebLLM is the default. It runs locally and only steers bounded room choices;
procedural generation keeps every room playable.
</p>
<label class="field">
<span>Provider</span>
<select id="provider-select">
<option value="browser" selected>Browser model · WebLLM</option>
<option value="offline">Procedural only · no AI</option>
<option value="openai">OpenAI-compatible · OpenRouter</option>
<option value="anthropic">Anthropic Claude</option>
</select>
</label>
<label class="field ai-depth-field">
<span class="ai-depth-heading">
<span>AI depth</span>
<output id="ai-depth-value" for="ai-depth-input">Standard · balanced</output>
</span>
<input
id="ai-depth-input"
type="range"
min="0"
max="2"
step="1"
value="1"
aria-describedby="ai-depth-note"
/>
<span id="ai-depth-note" class="browser-depth-note">
Adds authored room language while the next dream forms in the background.
</span>
</label>
<label class="field" id="model-field-browser">
<span>Browser model</span>
<select id="browser-model-select" aria-label="Browser WebLLM model"></select>
<span class="browser-depth-note">
Depth changes only the local AI's steering attempt—not room size,
scene complexity, effects, or catalog access. Every level gets the full game.
</span>
</label>
<label class="field hidden" id="model-field-cloud">
<span>Model</span>
<input
id="model-input"
type="text"
placeholder="openrouter/free"
autocomplete="off"
spellcheck="false"
/>
</label>
<label class="field cloud-field hidden" id="api-key-field">
<span>API key · this tab only</span>
<input
id="api-key-input"
type="password"
placeholder="sk-..."
autocomplete="off"
/>
</label>
<label class="field cloud-field hidden" id="base-url-field">
<span>Base URL</span>
<input
id="base-url-input"
type="url"
placeholder="https://openrouter.ai/api/v1"
autocomplete="off"
/>
</label>
<p class="help" id="provider-help">
Browser models run locally via WebGPU. The first load downloads model weights.
</p>
<button id="clear-key-btn" type="button" class="text-button cloud-field hidden">
Clear session key
</button>
</div>
</details>
<section class="rail-section">
<h2>Comfort & content</h2>
<label class="field field-inline">
<span>Graphics quality</span>
<select id="quality-select">
<option value="low">Low</option>
<option value="medium">Medium</option>
<option value="high" selected>High</option>
<option value="ultra">Ultra</option>
</select>
</label>
<p class="help">
Quality controls model detail density and how many objects each room
holds. Ultra needs a fast GPU; low keeps weaker hardware smooth.
</p>
<label class="check">
<input id="gore-toggle" type="checkbox" />
<span>Allow mild blood & gore</span>
</label>
<label class="check">
<input id="no-flashing-toggle" type="checkbox" />
<span>No flashing or pulsing lights</span>
</label>
<label class="check">
<input id="no-low-light-toggle" type="checkbox" />
<span>No low-light rooms</span>
</label>
<p class="help">
Comfort choices are enforced locally even when a model returns unusable output.
</p>
</section>
<section class="rail-section controls-section">
<h2>Controls</h2>
<dl class="control-grid">
<dt>Move</dt><dd><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd></dd>
<dt>Look</dt><dd>Mouse</dd>
<dt>Jump</dt><dd><kbd>Space</kbd></dd>
<dt>Sprint</dt><dd><kbd>Shift</kbd></dd>
<dt>Flashlight</dt><dd><kbd>F</kbd></dd>
<dt>Next dream</dt><dd><kbd>R</kbd></dd>
<dt>Pause</dt><dd><kbd>Esc</kbd></dd>
</dl>
<p class="help">Gamepad and touch controls are also supported.</p>
</section>
</div>
</aside>
</div>
<dialog
id="content-warning"
class="content-warning"
aria-labelledby="content-warning-title"
aria-describedby="content-warning-copy content-warning-source"
>
<div class="content-warning-frame">
<p class="eyebrow">AI content notice</p>
<h2 id="content-warning-title">Before you enter</h2>
<span class="brand-rule" aria-hidden="true"></span>
<div class="content-warning-copy">
<p id="content-warning-copy">
Kettermean uses generative AI and procedural systems. Rooms, signs, and
characters may be scary, nonsensical, unsettling, or occasionally seem
ill-intended.
</p>
<p id="content-warning-source">
Nothing is designed or prompted to offend, target, or harm anyone. Every
generation prompt is available in the public source for inspection.
</p>
</div>
<div class="content-warning-actions">
<button id="content-warning-continue" type="button" class="enter-button">
<span aria-hidden="true">→</span><span>Continue into dream</span>
</button>
<button id="content-warning-back" type="button" class="return-button">
Back to settings
</button>
</div>
</div>
</dialog>
<div id="pause-menu" class="pause-overlay hidden">
<section class="pause-rail" role="dialog" aria-modal="true" aria-labelledby="pause-title">
<p class="eyebrow">Dream suspended</p>
<h2 id="pause-title">Paused</h2>
<span class="brand-rule" aria-hidden="true"></span>
<dl class="pause-meta">
<div><dt>Room</dt><dd id="pause-room">Unknown threshold</dd></div>
<div><dt>Mood</dt><dd id="pause-mood">Static</dd></div>
<div><dt>Seed</dt><dd id="pause-seed">—</dd></div>
</dl>
<div class="pause-actions">
<button id="resume-btn" type="button" class="enter-button">
<span aria-hidden="true">→</span><span>Resume dream</span>
</button>
<button id="quit-btn" type="button" class="return-button">Return to threshold</button>
</div>
<div class="pause-controls">
<span>Move <kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd></span>
<span>Look Mouse</span>
<span>Flashlight <kbd>F</kbd> / gamepad X</span>
<span>Next dream <kbd>R</kbd> / gamepad Y</span>
<span>Pause <kbd>Esc</kbd></span>
</div>
</section>
</div>
</div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>