Build modern MacVenture‑style adventures with JSON + TypeScript

Promnesia is a tiny, batteries‑included engine that lets you define scenes, verbs, items, hot‑spots and logic in JSON, with optional TypeScript hooks when you need extra power. Ship to web, desktop, or mobile — no backend, no PHP, no database.

TypeScript core JSON world files Zero backend Canvas/WebGL renderers Web • Desktop • Mobile
{
  "id": "detective-office",
  "title": "Detective Office",
  "background": "assets/office.webp",
  "verbs": ["look","use","open","talk"],
  "hotspots": [
    { "id": "desk", "rect": [120,320,260,140], "on": {
        "look": "A heavy oak desk. Papers everywhere.",
        "use":  "You boot the computer. The fan squeals, then settles.",
        "open": "The drawer slides out: a brass key and a matchbook."
    }},
    { "id": "window", "rect": [620,100,260,160], "on": {
        "look": "Neon. Rain. The city hums.",
        "open": "It’s painted shut. Of course it is."
    }}
  ]
}
import type { Scene } from "promnesia";
export const DetectiveOffice: Scene = {
  id: "detective-office",
  onEnter(state) {
    state.music.play("nocturne");
  },
  script: {
    use_desk(state) {
      if (!state.flags.gotKey) {
        state.inventory.add("brass-key");
        state.flags.gotKey = true;
        state.ui.say("You pocket the brass key.");
      } else {
        state.ui.say("Nothing else worth taking.");
      }
    }
  }
};

Why Promnesia?

Built for rapid authoring, maintainability, and the cozy feel of classic MacVenture games—modernized for today.

💙 TypeScript core

Strict types, great DX, and modern tooling. Use JS/TS for logic when JSON isn’t enough.

🧾 JSON world files

Scenes, items, verbs, hotspots, conditions—human‑readable files that play nicely with Git.

🖼️ Pluggable renderers

Canvas2D by default. Swap in WebGL or your UI framework of choice for custom UIs.

💾 Save anywhere

Browser localStorage out of the box. Desktop/mobile builds can save to files.

🌍 Portable by design

Runs in modern browsers, Electron/Tauri on desktop, and Capacitor on mobile.

🧩 Extensible verbs

Define global verbs (Look, Use, Open, Talk) and scene‑specific behaviors.

🧠 Triggers & flags

Gate puzzles with conditions and flags—no giant switch statements.

🔤 Localization‑ready

Keep text in external catalogs; swap languages without touching logic.

🪶 Small footprint

Zero backend, no PHP, no DB. Serve as static files from any host or CDN.

Install & scaffold

You only need Node.js. Create a new project or add Promnesia to an existing frontend.

Quick start

# Create a new game
npx create-promnesia-app my-game
cd my-game
npm run dev

# Or add to an existing project
npm i promnesia-engine

Use via script tag

No bundler? Drop in a module script and reference your JSON world:

<script type="module">
  import {{ Promnesia }} from "https://cdn.example.com/promnesia/v1/mod.js";
  const world = await fetch("/game/world.json").then(r => r.json());
  const app = new Promnesia({{ target: "#game", world }});
  app.start();
</script>

Where it runs

  • Browsers: evergreen (ES2020+). Renders to Canvas2D/WebGL.
  • Desktop: Tauri or Electron wrappers for Windows, macOS, Linux.
  • Mobile: Capacitor targeting iOS/Android.
  • Tooling: Node.js for build scripts, exporters, and tests.
  • Hosting: Any static host (Netlify, Cloudflare Pages, GitHub Pages, S3, NGINX).

Promnesia ships with sensible defaults; you can layer any UI framework on top.

How it works

A simple data‑driven pipeline: describe your world, let the engine orchestrate.

1) JSON world files

Describe scenes, items, hotspots, verbs, transitions, and flags in JSON.

2) TypeScript core

Promnesia parses JSON, manages state (inventory, flags, scene stack), and emits UI events.

3) UI renderer

Default Canvas2D renderer + UI widgets. Swap in React/Svelte/Vue if you prefer.

Mini‑spec

A taste of the core types. Keep it boring (and beautiful) in JSON; sprinkle TS when needed.

Scene JSON

{
  "id": "alley",
  "title": "Rainy Alley",
  "background": "assets/alley.webp",
  "verbs": ["look","use","open","talk"],
  "hotspots": [
    { "id": "door", "rect": [520,300,150,200], "on": {
      "look": "A metal door with chipped paint.",
      "open": {"if": "!flags.hasKey", "say": "Locked."},
      "use":  {"if": "flags.hasKey", "goto": "backroom"}
    }},
    { "id": "cat", "rect": [160,420,120,80], "on": {
      "look": "A soaked alley cat. He blinks at you.",
      "talk": "Mrrrp? (He seems hungry.)"
    }}
  ]
}

TypeScript types

export type Verb = "look" | "use" | "open" | "talk";
export interface Hotspot {
  id: string;
  rect: [x: number, y: number, w: number, h: number];
  on: Partial;
}
export interface Scene {
  id: string;
  title?: string;
  background?: string;
  verbs?: Verb[];
  hotspots: Hotspot[];
}
export type Action =
  | { say: string }
  | { goto: string }
  | { give?: string; take?: string }
  | { if: string; then?: Action; else?: Action };

Live micro‑demo (in this page)

This tiny demo uses the same JSON idea: select a verb, then click an object.

Objects:
Try it: choose a verb and click an object.

Demo scene JSON

FAQ

Do I need a backend?

No. Promnesia games are just static assets (HTML, JS, JSON, images, audio). Host anywhere—no PHP, no database.

Can I script puzzles?

Yes. Keep most content in JSON. When you need custom logic, add small TypeScript handlers for verbs or scene hooks.

How do saves work?

In browsers we use localStorage by default. Desktop/mobile builds can save to files or OS‑native storage.

What about accessibility?

UI elements are keyboard‑friendly with ARIA labels. You can supply text alternatives for hotspots and support screen readers.

What tools ship with it?

A dev server, asset watcher, JSON validator, and exporter for web/desktop/mobile builds.

License?

Promnesia is designed for permissive, commercial‑friendly licensing. Use in hobby or commercial projects.

Ready to build something atmospheric?

Spin up a new project and start authoring scenes today.