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):
- 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) — this is what turns the touch from inert flavour into a rewarded habit. - 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.
- 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.
- The fold (uncommon) — the place pulls you back to level 0. A self-inflicted reset, curiosity's price. More likely the deeper you are.
- 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)
"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
exitto 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>|verba:<arc>|ix|<prop>|<kind>|<i>for kind in flashback / reaction / herring / folda:<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?}.foldsets level 0;false exitreturns the ending lines and resets progress for a fresh run. Neither reads or returns_has_anomaly. The commit endpoint/api/actis untouched.