Skip to content

opista/ur

Repository files navigation

🎲 The Royal Game of Ur — Digital Edition

A modern, online multiplayer recreation of the Royal Game of Ur — built with TypeScript, Next.js, NestJS, and React Three Fiber. Designed for async play (up to 7 days per turn), device-based persistence, and strong backend game validation.


🧩 Overview

This project brings the ancient Mesopotamian board game into the modern digital era — featuring:

  • Online 2-player asynchronous multiplayer
  • Turn-based play with 7-day timeout
  • Device-based identity (no login)
  • Backend-authoritative move validation
  • Beautiful 3D visuals rendered with React Three Fiber
  • Fully TypeScript-typed end-to-end

🏗️ Architecture

This is a Turborepo monorepo using pnpm workspaces:

game-of-ur/
│
├─ apps/
│   ├─ web/          # Next.js frontend (React + R3F)
│   └─ api/          # NestJS backend (game logic + state)
│
├─ packages/
│   └─ shared/       # Shared TypeScript types, Zod schemas, and core logic
│
├─ specs/            # Phase-by-phase build specs
│   ├─ phase0-setup.md
│   ├─ phase1-users.md
│   ├─ phase2-game-creation.md
│   ├─ phase3-game-rules.md
│   ├─ phase4-homepage.md
│   ├─ phase5-games-view.md
│   └─ phase6-game-board.md
│
├─ turbo.json
├─ docker-compose.yml  # Full local stack (web + api + postgres)
├─ pnpm-workspace.yaml
├─ tsconfig.json
├─ .editorconfig
└─ README.md

Tech Stack Summary

Layer Framework Key Libraries
Frontend Next.js (React, R3F, Drei, Framer Motion) TanStack Query, Zod
Backend NestJS class-validator, class-transformer, Zod
Shared TypeScript Game logic, Zod schemas
Monorepo TurboRepo + pnpm ESLint, Prettier, Jest, Vitest

⚙️ Core Concepts

🧠 1. Device-Based Identity

Each user is identified by a deviceSecret, generated server-side when they first visit the site.

  • Stored locally (in localStorage)
  • Never transferable or manually shareable
  • Used to authenticate moves and actions

🕹️ 2. Game Lifecycle

  1. Player A creates a game → receives a shareable link.
  2. Player B opens it → automatically joins as the second player.
  3. Both take turns rolling dice and making moves.
  4. If a player fails to move within 7 days, the other player wins automatically.

🎯 3. Backend-Authoritative Logic

  • Dice rolls, move validation, captures, and rosette rules handled entirely on the server.
  • Frontend never calculates legal moves independently.
  • Prevents cheating or move manipulation.

🎨 4. Frontend Experience

  • 3D board rendered via React Three Fiber + Drei.
  • Animated dice rolls and piece movements.
  • Async play with background polling for turn updates (no WebSocket in MVP).

📦 Monorepo Tooling

Tool Purpose
TurboRepo Pipeline management for build/lint/test/dev
pnpm Package manager
TypeScript (strict) Shared typing and validation
Zod Runtime schema validation
ESLint + Prettier Code consistency
Vitest + Jest Unit and integration testing
Husky + Lint-Staged Git pre-commit hooks
EditorConfig Editor consistency

🧪 Development Workflow

  1. Install deps:

    pnpm install
  2. Start via Docker:

    docker compose up
  3. Visit:


🔐 Environment Variables

Variable Used By Description
DATABASE_URL Backend PostgreSQL connection string
NEXT_PUBLIC_API_URL Frontend URL to backend (proxied via /api)
NODE_ENV All Environment (development/production)

Create an .env in /apps/api:

DATABASE_URL=postgres://ur:urpass@postgres:5432/urdb
NODE_ENV=development

🚧 Development Phases

The project is developed via spec-driven phases, each defined under /.spec. Each spec describes exactly what should be implemented before moving forward.

Phase Focus Status
Phase 0 Monorepo scaffolding, linting, testing setup ✅ Done
Phase 1 Device identity and persistence (deviceSecret model) ✅ Done
Phase 2 Game creation and joining logic ✅ Done
Phase 3 Game rules, dice rolls, and move logic ✅ Done
Phase 4 Homepage redesign with 3D clay tablet aesthetic ✅ Done
Phase 5 Games view wireframe and active games dashboard ✅ Done
Phase 6 Game board interface and 2D board rendering ✅ Done
Phase 7 3D board rendering and enhanced visuals ⏳ Next
Phase 8 Async multiplayer and turn timeouts 🔜
Phase 9 Polish, UX, and final improvements 🔜

🧭 Design Principles

  • Authoritative backend — all moves validated server-side
  • Stateless frontend — UI as reflection of game state
  • Strong typing across every layer
  • LLM-spec driven — each development phase fully documented
  • Incremental development — MVP first, extensibility later

🌐 Proxy Architecture

Frontend calls the backend through a local proxy:

// next.config.js
async rewrites() {
  return [
    { source: '/api/:path*', destination: 'http://localhost:3001/:path*' }
  ]
}

✅ Simplifies local dev (no CORS) ✅ Unified domain in production


🔮 Future Extensions

  • Real-time WebSocket updates
  • Cloud storage (PostgreSQL or Redis)
  • Replayable match history
  • Spectator mode
  • AI opponent mode
  • Mobile-friendly touch input

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages