Coding · NYU ITP · 2025

LOOP

A conversation with your future self.

I built a phone-simulation game where an unknown number claims to be you, 24 hours in the future. You decide whether to follow their instructions, warn a friend, or stop replying.

Stackp5.js · GPT-4o-mini · Web Audio API

The four strongest screens

LOOP's Unknown thread at 11:47 PM: You still awake? Good. Don't put the phone down. The player asks who this is, and Unknown answers it's you. from tomorrow., then i mean something happens tomorrow that you need to know about. The player says im calling the police; Unknown replies that won't help. just listen to me, okay?Jump to 02, the story engine
11:47 PM. “it's you. from tomorrow.”
LOOP Home Cameras screen at 12:08 am: Front Door live, Back Door last updated 3 seconds ago on a back yard infrared feed, and Bedroom Window offline on CAM 04 with a small grey MOTION labelJump to 01, the interface
Home Cameras. CAM 04, offline.
LOOP betrayal UI: notification banner reads 'Unknown: i know you're trying to text Jess. don't. i am you. i know.' appearing over the open Jess conversationJump to 03, the endings
Text Jess and Unknown knows at once.
Ending C, SOMEONE IS HERE: camera app turns deep red, Front Door shows SIGNAL LOST, Back Door shows BREACH DETECTED, Bedroom Window shows MOTION, RECORDINGJump to 03, the endings
Ending C: SOMEONE IS HERE.
Concept, jump to 01, the interface

LOOP looks 95% like a real iPhone.

That 5% is where it lives. Dread comes from familiarity.

Role · year, jump to role, process and impact

Design + Code

NYU ITP, Chatbots for Art's Sake. 2025.

Numbers, jump to 02, the story engine
3acts
7instructions
2sentences max
4endings
Three acts, jump to the three acts in 02

Calm, then urgent, then fragmenting.

Endings, jump to 03, the endings

Four endings, each triggered by a different kind of behavior.

Principles, jump to the principles in 01

Restraint over spectacle.

A reminders widget does the work distorted fonts do in cheap horror.

Voice, jump to the voice rules in 02

Two sentences, lowercase.

No metaphors, no exclamation points.

Outcome, jump to the impact

Four ways out.

Each choice leads to a different ending.

Learned, jump to 04, what I learned

What I learned.

  • Constraining the bot's voice was the hardest design problem.
  • The audience and the protagonist are the same person.

Role, process and impact

Role, process, impact and the context
Role
I built the phone interface, character prompts, story-state logic, and audio cues.
Process
I constrained the bot’s replies and tracked player choices in code to keep the branching conversation on course.
Impact
Players can follow the warnings, refuse them, contact a friend, or let the conversation time out. Each choice leads to a different ending.
Role
Design + Code
Context
NYU ITP · Chatbots for Art's Sake
Year
2025
Tags
  • p5.js
  • GPT-4o-mini
  • Web Audio API
  • Interactive Narrative

01Interface

The interface is the narrative.

  • Every visual choice is part of the story: the monospace clock, the reminders widget, the bedroom camera that stays offline until it doesn't.
  • LOOP looks 95% like a real iPhone; dread comes from familiarity.
  • Mundane reminders and a camera feed that says "Last Updated: 3 seconds ago" do the work that distorted fonts do in cheap horror.
Read more

Chatbots for Art's Sake

Every visual choice in LOOP is part of the story. The monospace clock. The reminders widget with "call dr. about appointment." The bedroom camera that stays offline for the entire game, until it doesn't. None of that is in the chat. The environment creates dread before the bot says a word.

LOOP looks 95% like a real iPhone. That 5% is where it lives. Dread comes from familiarity. The design principle is restraint over spectacle: the scariest version of this interface is the one that almost passes as normal. Cheap horror uses distorted fonts. LOOP uses mundane reminders and a camera feed that says "Last Updated: 3 seconds ago."

The interface

Every screen in LOOP is built from scratch in p5.js and HTML. The lock screen shows a real ticking time and a notification from "Unknown." The home screen has a reminders widget with items like "call dr. about appointment", mundane enough to feel real.

The home camera app shows three feeds: Front Door (live) and Back Door (last updated 3 seconds ago), both on infrared, and Bedroom Window, offline, with a small grey MOTION label in its corner. That camera goes offline as a design choice. Something is there. The game never explains it.

Screen cracks run down the right side of the phone frame. The audio layer adds glitch sounds, a pulsing alarm, and an iOS-style text ping. None of it is labeled. The wrongness is in the details.

Design principles

  1. The interface is the narrative. Every visual choice, the monospace font, the dark field, the cyan accent, is part of the story, not decoration around it. The game doesn't have a theme applied to a chat app. The chat app is the story.
  2. Restraint over spectacle. Dread comes from what is almost normal. The scariest version of this interface looks 95% like a real iPhone. No distorted fonts. No gore. A reminders widget with "call dr. about appointment" is more unsettling than any jump-scare.
  3. Every screen is a proof of work. The kind of detail a viewer zooms in on to see if it holds up. The camera timestamp. The unread badge count. The screen crack on the right side. It has to hold up. A portfolio piece that doesn't survive scrutiny isn't a portfolio piece.
LOOP home screen: reminders widget showing 'call dr. about appointment' and 'pick up prescription', dock with Messages (4 unread), Reminders, and Home Camera
HomeHome screen, reminders widget, dock, LOOP wordmark
LOOP Home Cameras screen at 12:08 am: Front Door live, Back Door last updated 3 seconds ago on a back yard infrared feed, and Bedroom Window offline on CAM 04 with a small grey MOTION label
CamerasHome Cameras, CAM 04 offline. Motion detected.

02Story engine

The prompt is mostly what the bot cannot say.

  • The bot is GPT-4o-mini on the NYU ITP/IMA proxy, driven by a 200-line system prompt across three acts.
  • It had to feel like a scared person texting at midnight: no metaphors, no exclamation points, no therapy-speak, never a capital letter, two sentences at most.
  • JavaScript tracks the acts (turn counts, silence timers, betrayal state); the code handles the state transitions.
Read more

The bot is GPT-4o-mini on the NYU ITP/IMA proxy. A 200-line system prompt drives three acts, each with its own voice rules and advancement conditions. The hardest design problem was the chatbot voice: it had to feel like a scared person texting at midnight, not a bot, not a philosopher.

That meant hard constraints: no metaphors, no exclamation points, no therapy-speak, never start with a capital letter, two sentences maximum. The prompt is more about what it cannot say than what it should. Act advancement is tracked in JavaScript, turn counts, silence timers, betrayal state, and the bot receives a tagged response; the code handles state transitions.

  • Fragmentation is intentional. As the story collapses in Act 3, the design earns the right to break. But only because Acts 1 and 2 held. The horror of Act 3's one-word messages is that you remember what full sentences felt like.
  • The paradox must be felt, not explained. LOOP never uses the words "time loop." The visual design makes you feel the loop before the text tells you about it, because if it had to be explained, it wouldn't land.
LOOP's Unknown thread at 11:47 PM: You still awake? Good. Don't put the phone down. The player asks who this is, and Unknown answers it's you. from tomorrow., then i mean something happens tomorrow that you need to know about. The player says im calling the police; Unknown replies that won't help. just listen to me, okay?
Act 1The Unknown thread at 11:47 PM: “it's you. from tomorrow.”

"who is this" / "it's you. from tomorrow." / "that makes no sense" / "i know. i said the same thing."

The opening exchange, Act 1

Three acts, in order

Each with its own voice rules and advancement conditions.

  1. ACT 1

    Calm. Careful.

    You're texting from an unknown number. Patient, lowercase, like someone who has had this conversation before and is trying to do it right this time.

  2. ACT 2

    Urgent. Controlling.

    Seven instructions, one at a time. Don't go outside 2–4pm. Don't answer the door. Let unknown calls ring. Each requires conversation before the next is given.

  3. ACT 3

    Fragmenting.

    Messages get shorter. Sometimes one word. Signal dropping. The loop closes. "there is no first version." The only exit: set a reminder for 11:47 tomorrow.

03Endings

Four endings, each triggered by a different kind of behavior.

  • The game tracks what you say, and also whether you opened the camera app, texted a contact or went silent.
  • The contacts list is fully interactive: open Jess, Tyler or Maya and type, and the unknown number already knows.
  • Ending D, the betrayal path, is the one players find by accident.
Read more

The game tracks not just what the player says in the main chat, but whether they opened the camera app, whether they tried texting a contact, whether they went silent. Four endings, each triggered by a different kind of behavior.

Ending D, the betrayal path, is the one players find by accident. The contacts list is fully interactive. You can open Jess, Tyler, Maya, and type. The game watches. If you try to warn someone else, the unknown number already knows.

LOOP betrayal UI: notification banner reads 'Unknown: i know you're trying to text Jess. don't. i am you. i know.' appearing over the open Jess conversation
Ending D, the turnWhen you tap any other contact and try to message them, Unknown fires a notification instantly. The code watches the messages list. Every contact click is intercepted.
Ending C, SOMEONE IS HERE: camera app turns deep red, Front Door shows SIGNAL LOST, Back Door shows BREACH DETECTED, Bedroom Window shows MOTION, RECORDING
Ending CEnding C, silence triggers the camera horror sequence. The bedroom window, offline all game, starts recording.

ENDING A

Break the Loop

You refuse to send the message. Tomorrow's version of you receives no warning. They go outside at 2pm. They answer the door.

ENDING B

Stay in the Loop

You set the reminder. Another version of you will receive this message at 11:47 tomorrow. The chain has no origin and no end.

ENDING C

You Became the Sender

Three silence timeouts. The bedroom window camera, offline, motion detected, comes to life. The horror sequence begins without you.

ENDING D

You Told Someone

You texted Jess to explain. The notification arrives instantly: "dont send that message to jess." The unknown number was watching the whole time.

04Reflection

The feeling of being observed is produced by observation.

LOOP is live on GitHub Pages.

Play LOOP ↗

Constraining the bot's voice was the hardest design problem.

Every LLM wants to be helpful, verbose, emotionally validating. Every line in the LOOP prompt had to fight that. The result, two sentences, lowercase, no metaphors, never say "I understand", was more about prohibition than prescription. The voice only worked once I stopped writing what the bot should say and started writing what it could never say.

Behavioral tracking is what makes interactive fiction feel authored.

Players who find Ending D almost always think the betrayal path was written just for them. That recognition, "it knew I would try that", is the game's best moment. It only exists because the code watches the messages list, the contacts, the silence timer. The feeling of being observed is produced entirely by observation.

The audience and the protagonist are the same person.

LOOP works because the player is alone, late at night, on a phone. The dread is personal. Portfolio viewers arrive as an audience and leave as participants. Players arrive as participants and leave with the uneasy feeling that the loop already started before they picked up the phone.