Skip to content

Repository files navigation

Drakenfall Online

A real-time, bilingual (es/en) text-based D&D game played in the browser. A single adventurer travels between Dawn Camp and a handful of cursed locations, each with its own town (store, player market, bounty, idle jobs) and its own infinite, procedurally generated wilds to explore. Combat is resolved with inline d20 skill checks. Spanish is the original UI language; English is the translation.

Stack

  • Frontend: React 18 + Vite, plain CSS3 (no Tailwind, no CSS framework), procedural inline-SVG art
  • Backend: Node + TypeScript, Hono with @hono/node-server (built-in WebSocket support)
  • Database: better-sqlite3 (synchronous, single connection, writes serialize)
  • Auth: HMAC-signed cookie sessions, guest login
  • i18n: react-i18next (client) + a t() helper (server); flat key maps in i18n/en.json / i18n/es.json
  • Tests: Vitest

Getting started

pnpm install
pnpm dev        # server (tsx watch) + client (vite) concurrently
pnpm test       # vitest run
pnpm build      # tsc typecheck + vite build
  • Server: http://localhost:8787, the Hono API and /ws WebSocket.
  • Client: http://localhost:5173, Vite dev server, proxies /api and /ws to the server.
  • The SQLite database (drakenfall.db, gitignored) is created and seeded on first run. For tests it runs in-memory (DB_PATH=:memory:).

Environment variables (all optional)

Variable Default Purpose
PORT 8787 HTTP/WS server port
DB_PATH ./drakenfall.db SQLite database file
SESSION_SECRET random (per boot) HMAC key for cookie sessions; set it so sessions survive restarts

Project layout

server/    Hono app: index.ts, db.ts, auth.ts, game.ts, chat.ts, routes.ts, ws.ts, i18n.ts
client/    React app: src/pages (Welcome, Create, World), src/components (ChatBox, art),
           GameContext.tsx, api.ts, ws.ts, i18n.ts, index.css, main.tsx, App.tsx
shared/    types.ts (DTOs + WS protocol), content.ts (locations, monsters, shop, jobs, choices)
i18n/      en.json, es.json (flat key maps, kept symmetric)
schema.sql additive migrations

Game model

  • Character creation asks only for a name, no class or gender. Every adventurer starts with a rusty dagger, 30 gold, and heads to Dawn Camp.
  • Locations: camp (safe hub, tier 0), old forest, ruined tower, mist marsh, mountain pass, black citadel (tiers 1–4). Each has its own town and its own wilds.
  • Town (per location):
    • Store, weapons and consumables; stock gated by the location's tier.
    • Player market, buy NPC-seeded listings, or list your own item for sale; listings you post are bought out by a simulated buyer after a short delay, paying you gold automatically.
    • Bounty, one hunting contract per location: defeat 3 creatures there for gold + XP (not available at Dawn Camp).
    • Jobs, idle timed tasks (gather firewood, mine ore, ...). One runs at a time, even while you do other things; claim its gold reward when the timer completes.
    • Rest, only at Dawn Camp; fully restores HP and energy.
  • Wilds: an infinite, procedurally generated hex map per location. Tiles (monster / loot / obstacle / empty) are generated deterministically when revealed, seeded per location, no edge to the map, and danger and rewards scale with distance from the entrance. Obstacles block movement.
  • Combat: stepping onto a monster tile starts a fight, resolved inline in the combat panel. Each attack is a d20 skill check: roll d20 + (level + weapon bonus) vs difficulty 10 + tile difficulty. Natural 20 = critical (double damage); natural 1 = fumble (extra damage taken); otherwise a hit lands if roll + bonus >= difficulty and the monster retaliates if it survives. Melee and ranged are labeled Might and Precision. Fleeing steps back to the last visited tile.
  • Defeating a monster grants gold and XP scaled to the tile's difficulty, clears the tile, reveals its neighbors, and advances any active bounty.
  • Energy is the action currency: every step and every attack costs 1. HP or energy hitting 0 triggers a collapse, you're dragged back to Dawn Camp, lose 15% of your gold (min 5), and recover to half HP / full energy.
  • XP curve 150 * level²; leveling up grants +4 max HP, +2 max energy, and a full heal.
  • Inventory equips/unequips melee and ranged weapons and uses consumables (HP/energy potions); unequipped gear returns to the pack.
  • Global chat is available from any screen, with seeded NPC chatter and auto-replies.

API & real-time

  • REST under /api: auth (guest, logout), and world actions, explore, attack, flee, travel, rest, buy, use, equip, unequip, missions, jobs, market, lang, chat, plus GET /api/world for the full WorldPayload.
  • WebSocket (/ws) pushes log (personal adventure log lines), event (world events), chat (global chat messages), presence, and ping.
  • Actions return an ActionResponse (ok, message, roll, bonus, difficulty, critical, monster, collapsed, event, …).

Conventions

  • No ORM, plain better-sqlite3 queries, typed DTOs in shared/types.ts.
  • Numbers are coerced to number in DTOs (SQLite returns strings).
  • All user-facing strings go through i18n keys (en.json/es.json, flat and symmetric); game content lives in typed modules in shared/content.ts with es/en localized fields.
  • Server-authoritative: only server/game.ts mutates state.
  • Deliberate simplifications are marked with ponytail: comments.
  • Dark-fantasy theme (Cinzel/Spectral, gold accents) in plain CSS3.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages