diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d6f23d5 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,31 @@ +name: CI + +# Typecheck, tests, and build on every PR and every push to main. +# Mirrors the CI in mateuseap/chesskernel so both apps gate the same way. + +on: + pull_request: + push: + branches: [main] + paths-ignore: + - '**.md' + - 'docs/**' + workflow_dispatch: + +permissions: + contents: read + +jobs: + build-test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + - uses: actions/setup-node@v4 + with: + node-version: 20 + cache: pnpm + - run: pnpm install --frozen-lockfile + - run: pnpm build # shared builds first so typecheck and tests resolve @pixelhub/shared + - run: pnpm typecheck + - run: pnpm test diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml index 27c5108..0dad51c 100644 --- a/.github/workflows/publish-images.yml +++ b/.github/workflows/publish-images.yml @@ -1,4 +1,4 @@ -name: Publish Images +name: Publish Images to GHCR on: push: diff --git a/README.md b/README.md index 105e3ba..3333cba 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,9 @@ **A virtual space you can actually walk around in.** 2D pixel world · Proximity chat · Self-hosted -[![CI](https://github.com/mateuseap/pixelhub/actions/workflows/publish-images.yml/badge.svg)](https://github.com/mateuseap/pixelhub/actions) +[![CI](https://github.com/mateuseap/pixelhub/actions/workflows/ci.yml/badge.svg)](https://github.com/mateuseap/pixelhub/actions) +[![Publish Images](https://github.com/mateuseap/pixelhub/actions/workflows/publish-images.yml/badge.svg)](https://github.com/mateuseap/pixelhub/actions) +[![version](https://badgen.net/github/tag/mateuseap/pixelhub?label=version&color=96bc4b)](https://github.com/mateuseap/pixelhub/releases) [![license](https://badgen.net/github/license/mateuseap/pixelhub?color=5ba3b0)](LICENSE) [![stars](https://badgen.net/github/stars/mateuseap/pixelhub)](https://github.com/mateuseap/pixelhub/stargazers) [![visitors](https://visitor-badge.laobi.icu/badge?page_id=mateuseap.pixelhub)](https://github.com/mateuseap/pixelhub) @@ -37,6 +39,29 @@ Video calls put everyone in a grid; real rooms let you drift between conversatio | 🎙 **Proximity Voice** | Self-hosted LiveKit SFU, audio-only Opus, volume falls off with distance | | 🐳 **Docker-first** | Multi-stage images, nginx WebSocket proxy, GHCR publishing | +## Architecture + +Three packages: a Phaser 3 client, an authoritative Colyseus server, and a shared pure-TypeScript core (map, collision, proximity, validation) that both sides import. The browser reaches the server through the client's nginx proxy; voice runs peer-to-SFU through self-hosted LiveKit. + +```mermaid +flowchart LR + browser(["browser: Phaser 3 client"]) + nginx["nginx client pod
static assets + /colyseus proxy"] + server["Colyseus server :2567
authoritative state, 20 ticks/s"] + shared["@pixelhub/shared
map, collision, proximity, validation"] + livekit["LiveKit SFU
audio-only, by avatar distance"] + + browser -->|HTTPS static| nginx + browser <-->|/colyseus WebSocket| nginx + nginx <--> server + server -.->|imports| shared + browser -.->|imports| shared + browser <-->|WebRTC audio| livekit + server -->|mints access tokens| livekit +``` + +Movement and chat are validated server-side at 20 ticks per second; the client predicts and interpolates. Chat and voice are proximity-scoped in `@pixelhub/shared`, so who you hear and read is a pure function of avatar distance. See [docs/architecture](docs/architecture/overview.md) for the full design. + ## Quick Start Requirements: Node >= 20 and pnpm >= 8 (`corepack enable` sets up pnpm).