A self-hosted research platform · v0.1

Branching
narratives,
observed.

Host your Twine 2 SugarCube stories as tracked experiments. Upload an HTML export, share a public link, and every passage, choice and save state lands neatly in your own database — under your roof, on your terms.

Twine 2 · SugarCube v2.37 Mongo · single tenant per researcher MIT · clone & run
tracked passage
by passage
§ 01 — workflow

From HTML export to participants in three steps.

No engine modification, no bespoke scripting. Drop in a Twine file, get a public play URL with a beacon-grade tracker injected automatically.

i.
Upload

Drop in your
SugarCube file.

The server validates the export, slugs the title, and injects the tracker after the script-sugarcube block — idempotently, so re-uploads stay byte-stable.

ii.
Share

Send the public
play URL.

Each story gets its own /play/<slug>. Drop a Prolific PID into the query string and resume kicks in automatically when the participant returns.

iii.
Collect

Export your
data, anytime.

Save blobs, click history, focus events and conditions are stored per-participant. Download the full study as JSON when you're ready to analyze.

§ 02 — principles

Built for researchers,
not for spectacle.

Multi-tenant by default, beacon-resilient by design, and small enough that you can audit every line that touches a participant's session.

α

Telemetry that survives the back button.

Save state is uploaded on every passage, plus on visibilitychange and pagehide via sendBeacon — so dropouts still produce a row in your dataset.

passage · hidden · pagehide
β

Resume that lands on the right passage.

Returning participants don't see a flash of the opening passage — the renderer is patched to repaint the resumed passage cleanly, every time.

storyready · engine.show()
γ

Workspaces that don't leak.

Every story, session, and exported dataset is owned by exactly one user. Listing endpoints filter by req.user._id — never by client-supplied owner. Public play URLs are the only unauthenticated read path, and they expose nothing about the researcher behind them.

multi-tenant · audited admin
δ

Conditions, branched.

Pass ?condition=… in the URL and the same story serves multiple experimental arms — no fork required.

one story · many arms
ε

Debrief on completion.

Configure ending passages and a debrief screen — or a redirect to your Prolific completion URL with templated tokens.

none · debrief · redirect
ζ

Auditable admin.

Admins see all studies and users, but inspecting another researcher's data is a deliberate, logged action — not a default capability.

role-gated · append-only log
§ 03 — sovereignty

Run it on your server.
One command, one researcher.

Clone the repo, run the interactive setup script, answer six prompts, and the platform is on the air. No SaaS account, no participant data crossing a vendor's wire.

Node 20 · Express 4 Mongo · local or hosted EJS · server-rendered
researcher@host · ~
$ git clone https://github.com/<you>/twine_platform
$ cd twine_platform && ./setup.sh

# answers six prompts: hostname, port, mongo URI,
# session secret, admin user, admin password

✓ wrote .env
✓ ensured indexes on users, stories, sessions
✓ seeded admin account

$ npm start
listening on https://your.research.host
Every choice a participant makes leaves a trace; the platform's only job is to keep that trace honest.
— design principle, project README

Ready to run your study?

Spin up a workspace on this instance, or clone the repo and host your own. Either way, your data stays where it should.

© 2026 · self-hosted instance SugarCube v2.37 · Node 20 · MIT