Artemis Lost is a full-stack sci-fi command game where an OpenAI-powered mission director reacts to a stranded lunar crew in crisis. Players assemble a crew, launch into the incident, and steer the story through role-based decisions, autonomous crew roles, evolving handoffs, and end-of-mission resolution.
The app now includes:
- a main menu with save-slot support
- player-first character creation for a four-role crew
- a launch sequence between setup and mission start
- human or autonomous control per crew role
- mission seed variation
- role-aware tactical suggestions and follow-through previews
- evolving crew coordination and handoff state
- win/loss resolution with distinct end screens
- durable save support through Postgres
- vault-backed prompt context
- structured state-delta updates from the DM
- Frontend: React + Vite
- Backend: Express / Node server
- Model provider: OpenAI Responses API or Anthropic Claude Messages API
- Persistence: browser-scoped slot saves plus vault-backed session mirrors
Install dependencies:
npm installCreate .env from .env.example:
cp .env.example .envThen fill in either OpenAI or Claude:
# OpenAI (default)
LLM_PROVIDER=openai
OPENAI_API_KEY=your_key_here
OPENAI_MODEL=gpt-4.1-mini
# Or Claude
# LLM_PROVIDER=anthropic
# ANTHROPIC_API_KEY=your_key_here
# ANTHROPIC_MODEL=claude-sonnet-4-6
DM_API_PORT=8787Start development:
npm run devBuild and preview:
npm run build
npm run previewRun the test suite:
npm install
npm testIf you see ERR_REQUIRE_ESM from html-encoding-sniffer, reinstall dependencies so jsdom@25 is used (not jsdom@29).
Run tests in watch mode:
npm run test:watchRun the production server locally:
npm run build
npm startThe production server serves both the built frontend and the /api routes from one Node process.
The repo is now set up for single-service deployment on hosts like Render or Railway.
Required environment variables:
# OpenAI
OPENAI_API_KEY=your_key_here
OPENAI_MODEL=gpt-4.1-mini
# Or Claude
LLM_PROVIDER=anthropic
ANTHROPIC_API_KEY=your_key_here
ANTHROPIC_MODEL=claude-sonnet-4-6Optional persistent storage variable:
DATA_DIR=/var/data/dungeonmaisterOptional durable database variable:
DATABASE_URL=postgres://user:password@host/dbname?sslmode=requireOperational endpoints:
GET /healthz: deployment health probe for the combined appGET /api/health: runtime status includingllmConfigured,llmProvider, and active model
Render path:
- Create a new
Web Servicefrom this repo. - Use the included
render.yaml, or set:- Build command:
npm install && npm run build - Start command:
npm start - Health check path:
/healthz
- Build command:
- Add
OPENAI_API_KEYand optionallyOPENAI_MODEL. - For durable saves, either:
- set
DATABASE_URLto a Neon/Postgres instance, or - mount a persistent disk and set
DATA_DIRto a folder on that disk.
- set
Deployment note:
- Static lore continues to load from the repository under
vault/static/. - With
DATABASE_URLset, save slots are stored durably in Postgres. - Save slots are scoped per browser/user via a local player id, so deployed users do not share the same three slots.
- Dynamic session mirrors for prompt context still write to a configurable data root.
- If neither
DATABASE_URLnorDATA_DIRis set, the app falls back to localvault/dynamic/behavior. - Cheapest durable path: Neon Postgres via
DATABASE_URL.
- Choose a save slot from the main menu.
- Create or load a mission.
- Claim one crew role by entering the player name and callsign.
- Generate the remaining crew around that player profile.
- Review or reroll the mission seed and crew details.
- Launch through the cinematic intro sequence.
- Submit actions on human turns while autonomous roles auto-play theirs.
- Use live tactical guidance, role-fit previews, and follow-through indicators to shape the next move.
- The DM returns narration plus a partial
STATE_DELTA. - The UI merges the update, applies local role and mission mechanics, resolves handoff-driven turn priority, updates the instrumented log, autosaves, and checks for mission resolution.
- Character creation with player insert, reroll, lock, and crew-dynamic inference
- Bank-driven crew generation with featured faculty easter eggs and authored overrides
- Mission seeds with scenario-specific mission, environment, systems, and opening event logs
- Mission-specific mechanics with per-seed leverage windows
- Autonomous crew roles for underfilled games
- Role-specific tactical guidance and clickable action suggestions
- Role mechanics, handoff windows, delegation strength, and evolving crew coordination
- Initiative overrides driven by handoffs and crew fit
- Instrumented event log with
command,system,sensor,trait, andrisktags - OpenAI-backed DM turn resolution
- Mission outcome rules with victory and defeat resolution screens
- Save slots, per-user persistence isolation, and vault-backed session mirrors
.
├── docs/
│ ├── ARCHITECTURE.md
│ ├── FEATURES.md
│ ├── GAMEPLAY_LOOP.md
│ └── INDEX.md
├── server/
│ ├── api.js
│ ├── dmServer.mjs
│ ├── prompts.js
│ ├── sessionMirrors.js
│ ├── sessionStorageAdapter.js
│ ├── sessionStore.js
│ ├── storagePaths.js
│ └── vault.js
├── src/
│ ├── app/
│ │ └── App.jsx
│ ├── components/
│ │ ├── ActionInput.jsx
│ │ ├── CrewCard.jsx
│ │ ├── CrewStatusBar.jsx
│ │ ├── EventLog.jsx
│ │ ├── NarrationPanel.jsx
│ │ ├── RoleView.jsx
│ │ ├── RosterSummary.jsx
│ │ ├── TelemetryBackdrop.jsx
│ │ └── TurnIndicator.jsx
│ ├── game/
│ │ ├── crewCoordination.js
│ │ ├── missionOutcome.js
│ │ ├── missionMechanics.js
│ │ ├── roleMechanics.js
│ │ ├── themes.js
│ │ ├── turnRuntime.js
│ │ └── worldState.js
│ ├── hooks/
│ │ └── useTypewriter.js
│ ├── screens/
│ │ ├── CharacterCreation.jsx
│ │ ├── LaunchSequence.jsx
│ │ ├── MainMenu.jsx
│ │ ├── MissionResolution.jsx
│ │ └── UI.jsx
│ ├── services/
│ │ ├── dmApi.js
│ │ └── sessionApi.js
│ ├── styles/
│ │ ├── interface.css
│ │ ├── motion.css
│ │ ├── responsive.css
│ │ ├── styles.css
│ │ └── tokens.css
│ └── main.jsx
├── vault/
│ ├── dynamic/
│ └── static/
├── tests/
└── README.md- Overview: docs/INDEX.md
- Features: docs/FEATURES.md
- Architecture: docs/ARCHITECTURE.md
- Gameplay loop: docs/GAMEPLAY_LOOP.md