File size: 8,218 Bytes
93a3c54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
<!-- 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.