Deploy Hallway 8 (multi-arc memory game)
Browse files- .gitattributes +1 -0
- CLAUDE.md +7 -1
- static/audio.js +7 -7
- static/audio/landing.ogg +3 -0
- static/style.css +32 -1
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
static/audio/landing.ogg filter=lfs diff=lfs merge=lfs -text
|
CLAUDE.md
CHANGED
|
@@ -98,7 +98,9 @@ The **landing** screen has its own quiet theme (`_landing`): a soft, slow vi-IV-
|
|
| 98 |
arpeggio, wistful fantasy, deliberately muted and background, never epic or eerie.
|
| 99 |
`window.ambience.play(skin)` starts on entering a loop (or `"landing"` on the
|
| 100 |
select screen); it stops/rebuilds on transitions. Landing audio starts on the
|
| 101 |
-
first user gesture (autoplay policy). An
|
|
|
|
|
|
|
| 102 |
`localStorage` (`h8_muted`). Audio only starts from a user gesture (browser
|
| 103 |
autoplay policy). To add a soundscape for a new arc, add a `_<skin>(bus)` builder
|
| 104 |
and branch to it in `play()`.
|
|
@@ -113,6 +115,10 @@ and branch to it in `play()`.
|
|
| 113 |
- **Doubt prompt** ("How certain are you?") appears randomly, more often near the
|
| 114 |
exit. Certain (≥3) commits; guessing (≤2) returns for exactly one re-decide.
|
| 115 |
- A "give up · back to start" link returns to the arc-selection landing.
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
|
| 117 |
## Shared tuning (engine-wide; see docs/ARCS.md for detail)
|
| 118 |
|
|
|
|
| 98 |
arpeggio, wistful fantasy, deliberately muted and background, never epic or eerie.
|
| 99 |
`window.ambience.play(skin)` starts on entering a loop (or `"landing"` on the
|
| 100 |
select screen); it stops/rebuilds on transitions. Landing audio starts on the
|
| 101 |
+
first user gesture (autoplay policy). An exported render of the landing theme is
|
| 102 |
+
saved at `static/audio/landing.ogg` (mono OGG Vorbis, ~42s, normalized; rendered
|
| 103 |
+
offline from the same synth via OfflineAudioContext). An always-visible mute toggle (`#sound-toggle`) persists to
|
| 104 |
`localStorage` (`h8_muted`). Audio only starts from a user gesture (browser
|
| 105 |
autoplay policy). To add a soundscape for a new arc, add a `_<skin>(bus)` builder
|
| 106 |
and branch to it in `play()`.
|
|
|
|
| 115 |
- **Doubt prompt** ("How certain are you?") appears randomly, more often near the
|
| 116 |
exit. Certain (≥3) commits; guessing (≤2) returns for exactly one re-decide.
|
| 117 |
- A "give up · back to start" link returns to the arc-selection landing.
|
| 118 |
+
- **Mobile** (`@media max-width:640px`): the layout top-aligns (`align-items:
|
| 119 |
+
flex-start`) instead of centering, because centered flex clips the top HUD when
|
| 120 |
+
content is taller than the viewport. `#screen` gets `padding-top` to clear the
|
| 121 |
+
fixed sound toggle. Keep the progress HUD visible; don't reintroduce centering.
|
| 122 |
|
| 123 |
## Shared tuning (engine-wide; see docs/ARCS.md for detail)
|
| 124 |
|
static/audio.js
CHANGED
|
@@ -122,18 +122,18 @@ class Ambience {
|
|
| 122 |
const now = this.ctx.currentTime;
|
| 123 |
// mains buzz: a low hum plus a thin harmonic
|
| 124 |
const hum = this._osc("sine", 120);
|
| 125 |
-
const humG = this._gain(0.
|
| 126 |
hum.connect(humG).connect(bus);
|
| 127 |
const harm = this._osc("triangle", 240);
|
| 128 |
-
const harmG = this._gain(0.
|
| 129 |
harm.connect(harmG).connect(bus);
|
| 130 |
// faint high whine
|
| 131 |
const whine = this._osc("sine", 8200);
|
| 132 |
-
const whineG = this._gain(0.
|
| 133 |
whine.connect(whineG).connect(bus);
|
| 134 |
// ventilation: brown-ish noise, low-passed
|
| 135 |
const vent = this._noise(4);
|
| 136 |
-
const ventG = this._gain(0.
|
| 137 |
vent.connect(this._filter("lowpass", 320, 0.7)).connect(ventG).connect(bus);
|
| 138 |
[hum, harm, whine, vent].forEach((s) => s.start(now));
|
| 139 |
// a flicker, but rare (roughly once a minute) and soft: a small dip in the
|
|
@@ -141,13 +141,13 @@ class Ambience {
|
|
| 141 |
this._every(50000, 90000, () => {
|
| 142 |
const t = this.ctx.currentTime;
|
| 143 |
humG.gain.setValueAtTime(humG.gain.value, t);
|
| 144 |
-
humG.gain.linearRampToValueAtTime(0.
|
| 145 |
-
humG.gain.linearRampToValueAtTime(0.
|
| 146 |
const cr = this._noise(0.2);
|
| 147 |
const crG = this._gain(0);
|
| 148 |
cr.connect(this._filter("highpass", 2000)).connect(crG).connect(bus);
|
| 149 |
cr.start(t);
|
| 150 |
-
crG.gain.setValueAtTime(0.
|
| 151 |
crG.gain.exponentialRampToValueAtTime(0.0004, t + 0.12);
|
| 152 |
cr.stop(t + 0.2);
|
| 153 |
});
|
|
|
|
| 122 |
const now = this.ctx.currentTime;
|
| 123 |
// mains buzz: a low hum plus a thin harmonic
|
| 124 |
const hum = this._osc("sine", 120);
|
| 125 |
+
const humG = this._gain(0.021);
|
| 126 |
hum.connect(humG).connect(bus);
|
| 127 |
const harm = this._osc("triangle", 240);
|
| 128 |
+
const harmG = this._gain(0.0084);
|
| 129 |
harm.connect(harmG).connect(bus);
|
| 130 |
// faint high whine
|
| 131 |
const whine = this._osc("sine", 8200);
|
| 132 |
+
const whineG = this._gain(0.0018);
|
| 133 |
whine.connect(whineG).connect(bus);
|
| 134 |
// ventilation: brown-ish noise, low-passed
|
| 135 |
const vent = this._noise(4);
|
| 136 |
+
const ventG = this._gain(0.035);
|
| 137 |
vent.connect(this._filter("lowpass", 320, 0.7)).connect(ventG).connect(bus);
|
| 138 |
[hum, harm, whine, vent].forEach((s) => s.start(now));
|
| 139 |
// a flicker, but rare (roughly once a minute) and soft: a small dip in the
|
|
|
|
| 141 |
this._every(50000, 90000, () => {
|
| 142 |
const t = this.ctx.currentTime;
|
| 143 |
humG.gain.setValueAtTime(humG.gain.value, t);
|
| 144 |
+
humG.gain.linearRampToValueAtTime(0.012, t + 0.04);
|
| 145 |
+
humG.gain.linearRampToValueAtTime(0.021, t + 0.25);
|
| 146 |
const cr = this._noise(0.2);
|
| 147 |
const crG = this._gain(0);
|
| 148 |
cr.connect(this._filter("highpass", 2000)).connect(crG).connect(bus);
|
| 149 |
cr.start(t);
|
| 150 |
+
crG.gain.setValueAtTime(0.014, t);
|
| 151 |
crG.gain.exponentialRampToValueAtTime(0.0004, t + 0.12);
|
| 152 |
cr.stop(t + 0.2);
|
| 153 |
});
|
static/audio/landing.ogg
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:c3848234bf5e8eb9b66d050cd8c17ebd155bf651066719c30fd6baa279bffbc9
|
| 3 |
+
size 295875
|
static/style.css
CHANGED
|
@@ -313,6 +313,37 @@ body {
|
|
| 313 |
}
|
| 314 |
|
| 315 |
@media (max-width: 640px) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 316 |
.title { font-size: 2.2rem; }
|
| 317 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 318 |
}
|
|
|
|
| 313 |
}
|
| 314 |
|
| 315 |
@media (max-width: 640px) {
|
| 316 |
+
/* Top-align instead of centering: centered flex clips the top (the HUD) when
|
| 317 |
+
content is taller than the viewport. Top-align keeps the progress bar
|
| 318 |
+
visible and lets the page scroll naturally. */
|
| 319 |
+
body {
|
| 320 |
+
align-items: flex-start;
|
| 321 |
+
justify-content: flex-start;
|
| 322 |
+
}
|
| 323 |
+
#screen {
|
| 324 |
+
padding: 1.1rem;
|
| 325 |
+
padding-top: 3rem; /* clear the fixed sound toggle */
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
.title { font-size: 2.2rem; }
|
| 329 |
+
.select-lead { font-size: 0.95rem; }
|
| 330 |
+
.brief { min-height: 0; margin-bottom: 1.5rem; }
|
| 331 |
+
|
| 332 |
+
/* progress bar: smaller, always readable, wraps rather than hides */
|
| 333 |
+
.hud {
|
| 334 |
+
font-size: 0.68rem;
|
| 335 |
+
letter-spacing: 0.12em;
|
| 336 |
+
margin-bottom: 1.6rem;
|
| 337 |
+
flex-wrap: wrap;
|
| 338 |
+
gap: 0.2rem 0.8rem;
|
| 339 |
+
}
|
| 340 |
+
.progress { font-weight: 500; }
|
| 341 |
+
|
| 342 |
+
.heading { font-size: 1.25rem; margin-bottom: 1.6rem; }
|
| 343 |
+
.prose { font-size: 1.02rem; line-height: 1.95; min-height: 7rem; }
|
| 344 |
+
.controls { margin-top: 1.8rem; }
|
| 345 |
+
.give-up-row { margin-top: 2.2rem; }
|
| 346 |
+
.arcs { margin-top: 1.5rem; }
|
| 347 |
+
|
| 348 |
+
.sound-toggle { top: 0.5rem; right: 0.5rem; opacity: 0.6; }
|
| 349 |
}
|