|
Download docs/ACT2.md from alvations/hallway8: direct link, hf CLI and curl.
- Browser
- Download file 8.22 kB
-
https://huggingface.co/spaces/alvations/hallway8/resolve/main/docs/ACT2.md
- Command line
-
hf download hf://spaces/alvations/hallway8/docs/ACT2.md
-
curl -L -o ACT2.md https://huggingface.co/spaces/alvations/hallway8/resolve/main/docs/ACT2.md
8.22 kB
| <!-- SPDX-License-Identifier: Apache-2.0 --> | |
| <!-- Copyright 2026 alvations (Melon Lab) --> | |
| # Act 2: the interactions ("touch the room") | |
| Act 1 is the memory loop: read the place, decide **go on** or **turn back**, | |
| eight correct calls escape, one wrong call resets. That never changes. | |
| Act 2 is an optional layer on top: some details in the scene can be **touched** | |
| (a verb per detail), and touching them deepens the story and the dread without | |
| altering the win math. This document is the design of record. Read it before | |
| adding interaction content to an arc. | |
| ## The one iron rule | |
| **Interactions never change the forward/back judgement.** Correctness is still | |
| `correct = (choice == "back") == has_anomaly`, computed only when the player | |
| commits. Touching a detail can, very rarely, restart the run or end it in a wrong | |
| ending, but it never decides the go-on/turn-back call, and it never reveals | |
| whether the place changed. In almost every case touching changes nothing | |
| mechanical; the player then makes the normal call, and that call is **go on as | |
| often as turn back**. The interaction never tells you which. The one moment where | |
| "just turn back and ignore it" is the lesson is the false exit below, and that is | |
| made so rare it almost never happens. | |
| ## The five outcomes of a touch | |
| When a detail is touched, the server rolls one outcome (weighted by level, never | |
| by the detail's actual state, so it cannot be used as a detector): | |
| 1. **Flashback** (common) — a fragment of backstory, then back to the loop. | |
| Free lore, no mechanical effect. Each fragment is **collected**: the client | |
| records its index and text, fills a dot on the Collectibles ledger, and lets | |
| the player recall its words later. Seeing every fragment in an arc earns a | |
| badge (see [`COLLECTION.md`](COLLECTION.md)) — this is what turns the touch | |
| from inert flavour into a rewarded habit. | |
| 2. **Neutral reaction** (common) — the world responds and tells you nothing (you | |
| wave, the camera swivels; you call out, the figure may turn). Happens whether | |
| or not the detail is the anomaly this loop. | |
| 3. **Red-herring reaction** (common) — a *false clue*: a sensory detail that | |
| reads as evidence and is not (the poster is freshly printed, the seat is still | |
| warm). It appears on normal loops exactly as often as on changed ones, so it | |
| misleads as much as it "helps". Raises doubt, never resolves it. | |
| 4. **The fold** (uncommon) — the place pulls you back to level 0. A self-inflicted | |
| reset, curiosity's price. More likely the deeper you are. | |
| 5. **The false exit** (very rare, trigger-gated) — the run ends in a *wrong* | |
| ending, never a win. This is NOT a low-percentage roll on every touch: a "way | |
| out" dressed as salvation only *appears* on ~7% of loops around the | |
| three-quarter mark (levels 6-7), not near the finish, and it only fires if the | |
| player chooses to take it instead of turning back. Ignore it, which is the | |
| right move, and nothing happens. Most runs never see one. | |
| Weighting (defaults; all tunable in one place in `hallway.py`). An ordinary | |
| touch rolls only flavour vs fold: | |
| | Level band | flashback / neutral / red-herring | fold (reset to 0) | | |
| |---|---|---| | |
| | L1–2 | 100% | 0% | | |
| | L3–5 | ~90% | ~10% | | |
| | L6–8 | ~85% | ~15% | | |
| Levels 1–2 are pure, safe flavour: touching only ever gives a flashback or a | |
| reaction, so the player learns the verb without risk. **From level 3 the | |
| different consequences become triggerable** (the fold appears), rising to ~15% at | |
| the bottom: a deep sting, never frequent. Whatever the outcome, **the touch is | |
| always optional, and in most cases the player just ignores it and commits | |
| forward or backward as normal.** | |
| **The false exit is separate and gated, not a per-touch percentage:** | |
| - it can only involve the **one exit-capable detail per arc** (Hallway's lit | |
| EXIT door, Stairway's shortcut landing door, Coach's carriage door onto a | |
| platform), | |
| - the "way out dressed as salvation" only *appears at all* on **~7%** of loops | |
| around the **three-quarter mark (levels 6–7)**, not near the finish (rare | |
| enough to stay a discovery across runs, common enough that a player who keeps | |
| playing will eventually meet one). The | |
| temptation should bite when the end is in sight but not imminent. It is | |
| **visually distinct** so taking it is always a deliberate choice, never a | |
| misclick, | |
| - even when it appears it does nothing unless the player **chooses to take it**; | |
| turning back or going on normally makes it evaporate. | |
| Net effect: most runs never surface one, and most players who do surface one | |
| ignore it. It stays a whispered secret, not a resented punishment. | |
| ## What the player sees | |
| Only details actually shown this loop can be touched, so the available verbs | |
| rotate with the scene (usually one or two). Each is a quiet contextual control | |
| next to the loop, separate from the two commit buttons. Touching shows a short | |
| line; the player then still makes the normal go-on/turn-back call. A given detail | |
| can be touched once per loop. | |
| Verbs are per-detail and themed, not always "open a door": | |
| - **Hallway 8:** try the maintenance door · wave at the camera · look closer at | |
| the poster · call out to the man in grey. | |
| - **Coach 8:** open the luggage · look out the window · read the scratched note · | |
| nudge the sleeping passenger. | |
| - **Stairway 8:** look out the landing window · read the scratches on the wall · | |
| grip the handrail · call down the stairwell. | |
| ## The story Act 2 tells | |
| The touches are the game's soul: they are the player's own memory, offering lore, | |
| a false way out, or a fold back to the start. The through-line (per arc) is that | |
| the player has done this walk before and the openings along it are not exits, | |
| they are memories of leaving that the place keeps open because an easy lie is | |
| more tempting than remembering why they are still here. See the per-arc | |
| `interactions` (flashbacks) and `alt_endings` (false exits) in the arc JSON for | |
| the concrete fragments and endings. | |
| ## Content schema (per arc JSON) | |
| ```jsonc | |
| "interactions": { | |
| "<prop>": { | |
| "verb": "try the door", // the contextual control label | |
| "flashback": ["...", "..."], // outcome pools; picked by the roll | |
| "reaction": ["...", "..."], // neutral reactions | |
| "herring": ["...", "..."], // red-herring reactions | |
| "fold": ["..."], // flavour shown as the place folds you | |
| "exit": "break_room" // OPTIONAL: this prop can be the rare | |
| // false exit -> alt_endings["break_room"] | |
| } | |
| }, | |
| "alt_endings": { | |
| "break_room": ["...", "...", "..."] // the wrong-ending screen text | |
| } | |
| ``` | |
| Rules for content: | |
| - Keep flavour lines **state-agnostic**: they must read the same whether or not | |
| the prop is the anomaly (the server never passes the state in). This is what | |
| makes a touch un-cheatable. | |
| - Only give `exit` to a detail that can plausibly look like a way out (a door, a | |
| window, a platform), and only one or two per arc. | |
| - No em-dashes; no spoilers in the loop UI or intro (players discover the touch, | |
| and discover it changed nothing, on their own). | |
| ## Keys and localization | |
| The interaction strings get deterministic keys via `i18n.arc_items`: | |
| - `a:<arc>|ix|<prop>|verb` | |
| - `a:<arc>|ix|<prop>|<kind>|<i>` for kind in flashback / reaction / herring / fold | |
| - `a:<arc>|end|<id>|<i>` for the alternate endings | |
| They localize through the normal pipeline (`docs/LOCALIZATION.md`) and fall back | |
| to English key by key until translated, so Act 2 can ship in English first and be | |
| localized after. They do not enter the level-composition QE gate (that composes | |
| only loop prose), so translate them with per-line QE when the time comes. | |
| ## Server / client contract | |
| - The public room carries `interactions: [{prop, verb}]` for the shown, | |
| touchable props (no answer leak; interactability is static per prop, never a | |
| function of the anomaly). | |
| - `POST /api/interact {prop}` rolls an outcome and returns | |
| `{kind, line, level, goal, ending?}`. `fold` sets level 0; `false exit` returns | |
| the ending lines and resets progress for a fresh run. Neither reads or returns | |
| `_has_anomaly`. The commit endpoint `/api/act` is untouched. | |