Skip to content

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Latest commit

 

History

83 Commits

Folders and files

Repository files navigation

Art Thieves

Multiplayer location-based tag game built with Expo (React Native) and a Node.js/Socket.IO server.

Prerequisites

  • Node.js 18+
  • npm
  • Android: Android Emulator (AVD) or a physical Android device
  • iOS (macOS only): Xcode with the iOS Simulator, plus CocoaPods
  • Windows (for included scripts) or manual configuration for macOS/Linux

Setup

# Install server dependencies
cd server
npm install

# Install app dependencies
cd ../app
npm install

Running (development)

1. Start the server

cd server
npm run dev

Starts on http://localhost:3001.

2. Start the app

iOS (macOS only)

cd app
npx expo run:ios

Builds the native project, installs CocoaPods dependencies, and launches the app on the first available iOS Simulator. You can pick a specific simulator with:

npx expo run:ios --device "iPhone 16 Pro"

If CocoaPods is missing, install it first:

sudo gem install cocoapods
cd app/ios && pod install

Android

cd app
npx expo run:android

Builds and installs the app on the first available emulator. To install on a second emulator, use:

npx expo run:android          # installs on emulator 1
adb install -r android/app/build/outputs/apk/debug/app-debug.apk

Then open the app manually on the second emulator. Both instances reload from the same Metro dev server.

Physical device

Set EXPO_PUBLIC_API_URL in app/.env to your computer's LAN IP on port 3001, start the server, then:

# Android
cd app
npx expo run:android --device

# iOS
npx expo run:ios --device

On iOS you must select a signing team: open app/ios/VancouverArtThieves.xcworkspace in Xcode, go to the "VancouverArtThieves" target → Signing & Capabilities, and set your Apple ID team. The iOS Simulator needs no signing.

Architecture

  • server/ — Express + Socket.IO backend with selectable memory, SQLite, or PostgreSQL storage
  • app/ — Expo React Native app with Zustand stores, MapLibre maps, and Socket.IO client

Configuration

All environment variables for the app (app/.env) and the server (server/.env) are documented in ENV.md — including the storage driver, database connection settings, the API base URL, and the map style. Templates with every option live in app/.env.example and server/.env.example.

Game settings (duration, vicinity radius, no-tag grace period, etc.) are configurable by the host when creating a game.

Database backends

The server selects its storage backend at startup with DB_DRIVER:

# Local persistent development (default)
DB_DRIVER=sqlite
DATABASE_PATH=./data/vat.db

# Azure or another managed PostgreSQL service
DB_DRIVER=postgres
DATABASE_URL=postgresql://user:password@host:5432/art_thieves

# Ephemeral development/testing
DB_DRIVER=memory

PostgreSQL uses the migrations in server/drizzle-postgres/. Existing SQLite data is not copied automatically; export and import it before switching a production deployment. Uploaded photos remain filesystem data and should use durable storage such as Azure Files or Blob Storage in production.

To copy an existing SQLite database into a migrated PostgreSQL database, set both DATABASE_PATH and DATABASE_URL, then run:

cd server
npm run db:migrate:sqlite-to-postgres

The command copies database records only. Copy the corresponding uploads/ files separately.

Self-host the server (Docker)

A ready-to-run image is published to GitHub Container Registry as ghcr.io/lo3wer/vancouver-art-thieves-server (multi-arch: linux/amd64 + linux/arm64), tagged on each v* release plus a rolling latest. No build tools needed on the host.

Quick start

docker run -d --name art-thieves \
  -p 3001:3001 \
  -v art-thieves-data:/data \
  -v art-thieves-uploads:/app/uploads \
  ghcr.io/lo3wer/vancouver-art-thieves-server:latest

The server listens on http://<host>:3001. With the default SQLite driver, it creates the database, runs migrations, and seeds a default map. The database lives in the art-thieves-data volume and uploaded photos in art-thieves-uploads — both survive restarts and upgrades.

Environment variables

Variable Default Purpose
PORT 3001 HTTP/Socket.IO listen port
DB_DRIVER sqlite memory, sqlite, or postgres
PERSIST true Legacy switch; false selects memory
DATABASE_PATH /data/vat.db SQLite database file path
DATABASE_URL unset PostgreSQL connection URL
MIGRATIONS_DIR ./drizzle Drizzle migrations folder (in the image)
POSTGRES_MIGRATIONS_DIR ./drizzle-postgres PostgreSQL migrations folder
UPLOADS_DIR /app/uploads Folder for uploaded game photos

HTTPS (production)

The image serves plain HTTP on port 3001. Put a reverse proxy in front for TLS. Example with Caddy (auto HTTPS):

services:
  app:
    image: ghcr.io/lo3wer/vancouver-art-thieves-server:latest
    restart: unless-stopped
    volumes:
      - art-thieves-data:/data
      - art-thieves-uploads:/app/uploads
  caddy:
    image: caddy:2-alpine
    restart: unless-stopped
    ports: ["80:80", "443:443"]
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
      - caddy_config:/config
    depends_on: [app]
volumes:
  art-thieves-data:
  art-thieves-uploads:
  caddy_data:
  caddy_config:

with a Caddyfile like:

your.domain.com {
  reverse_proxy app:3001
}

Point the app at your server

Set EXPO_PUBLIC_API_URL in app/.env to your server URL (e.g. https://your.domain.com/) and rebuild the app. EXPO_PUBLIC_* values are baked in at build time.

About

No description, website, or topics provided.

Resources

Stars

3 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages