197 lines
7.7 KiB
Markdown
197 lines
7.7 KiB
Markdown
# I Want To Heal — Thor healer roguelike
|
||
|
||
Playable low-poly third-person combat vertical slice for AYN Thor's dual displays.
|
||
|
||
Offline-first frontend includes three timestamped save slots, TrueNAS accounts
|
||
and cloud saves, Hunter Profile statistics, boss and roguelike leaderboards,
|
||
boss collection logs, Settings, and PvE/PvP mode entry points. Offline saves
|
||
remain playable without an account and can be uploaded after sign-in.
|
||
|
||
## Run
|
||
|
||
```bash
|
||
pnpm install
|
||
pnpm dev:api
|
||
# In a second terminal:
|
||
pnpm dev
|
||
```
|
||
|
||
The Vite development server listens on `0.0.0.0:4173` and proxies `/api` to the
|
||
local production/API server on `127.0.0.1:4174`. Both processes use the same
|
||
client API contract as TrueNAS.
|
||
|
||
## Android / AYN Thor test APK
|
||
|
||
The Android host uses Capacitor, locks to landscape, requests immersive mode and
|
||
60 Hz, and sends controller input directly to the game WebView. Build an
|
||
installable debug APK:
|
||
|
||
```bash
|
||
pnpm android:apk
|
||
```
|
||
|
||
Build explicitly against the TrueNAS API with `pnpm android:apk:truenas`.
|
||
Native builds also default to `https://iwanttoheal.phenomrom.com` when no API
|
||
base override is supplied.
|
||
|
||
Output is written under `android/app/build/outputs/apk/debug/`. With Android
|
||
platform tools and a connected Thor, build and install it with:
|
||
|
||
```bash
|
||
pnpm android:install
|
||
```
|
||
|
||
The Android host routes the main and tactical surfaces to separate physical
|
||
Thor displays while preserving one authoritative game state. If only one
|
||
display is available, Select (or Tab with a keyboard) opens the tactical surface
|
||
over the main game view.
|
||
|
||
PC and handheld browsers use the Thor top screen as a responsive, full-viewport
|
||
game surface. The compact ability strip keeps combat controls visible; Select
|
||
or Tab opens party, map, inventory, and other tactical detail. Use
|
||
`?layout=thor-preview` to restore the stacked dual-screen hardware mockup for
|
||
browser QA.
|
||
|
||
## TrueNAS deployment
|
||
|
||
Complete first-install, local-Gitea clone, YAML, update, and verification steps:
|
||
[DEPLOYMENT.md](DEPLOYMENT.md).
|
||
|
||
The live TrueNAS web server uses the existing deployment address and port:
|
||
|
||
- Public URL: `https://iwanttoheal.phenomrom.com`
|
||
- Host/container port: `4173`
|
||
- App directory: `/mnt/usbssds/apps/iwanttoheal-mmo/app`
|
||
|
||
### Server architecture
|
||
|
||
TrueNAS is the online production game server. Its Node process serves the browser
|
||
application and authenticated `/api` routes on port `4173`; the reverse proxy
|
||
exposes both at the public URL above. SQLite data persists at `/app/data/game.db`
|
||
through the separate TrueNAS data mount.
|
||
|
||
The server owns account credentials, 30-day sessions, three cloud-save slots per
|
||
account, boss-kill rankings, and roguelike highest-round rankings. Passwords use
|
||
scrypt with per-account salts; clients store only opaque session tokens. Local
|
||
saves remain available for offline play. Gitea is a separate TrueNAS service used
|
||
for source hosting and deployment.
|
||
|
||
Clone from the TrueNAS-local Gitea bare repository into the app directory, then
|
||
deploy `compose.yaml`. The expected source path is:
|
||
|
||
```text
|
||
/mnt/.ix-apps/app_mounts/gitea/data/git/repositories/phenom/i-want-to-heal-mmo.git
|
||
```
|
||
|
||
Current configuration:
|
||
|
||
- use `corepack pnpm install --frozen-lockfile`, not `npm ci`;
|
||
- run `pnpm db:init` before starting the production server;
|
||
- mount `/mnt/usbssds/apps/iwanttoheal-mmo/data` at `/app/data`;
|
||
- keep `CORS_ORIGINS` configured for the public site and Capacitor host;
|
||
- keep the source checkout and persistent data in separate mounts.
|
||
|
||
The existing reverse proxy forwards the public hostname to port `4173`, including
|
||
all `/api` routes.
|
||
|
||
## Publish updates to Gitea
|
||
|
||
The repository target is:
|
||
|
||
```text
|
||
https://git.whoagland.com/phenom/i-want-to-heal-mmo.git
|
||
```
|
||
|
||
Create `git-token` in the repository root. Paste only the Gitea token into it:
|
||
|
||
```text
|
||
gitea_token_value_goes_here
|
||
```
|
||
|
||
Do not add quotes or a `GITEA_TOKEN=` prefix. The exact `/git-token` path is
|
||
Git-ignored. Restrict local file access with `chmod 600 git-token`. The publisher
|
||
reads it automatically. `GITEA_TOKEN` remains available as an optional override.
|
||
Publish from `main` normally:
|
||
|
||
```bash
|
||
pnpm publish:gitea -- --message "Describe the update"
|
||
```
|
||
|
||
The script installs locked dependencies, builds the web app, runs web and Android
|
||
checks, builds a debug APK, commits all project changes, pushes `main`, creates a
|
||
version tag and Gitea prerelease, and uploads the APK plus its SHA-256 file. It
|
||
uses `package.json` version unless that version is already tagged, then advances
|
||
the patch number. Pass `--version 0.2.0` to choose an explicit version.
|
||
|
||
If the publisher runs where TrueNAS paths are visible, it prefers a
|
||
fast-forward-only pull directly from TrueNAS-local Gitea storage. Otherwise it
|
||
prints the exact local clone/pull commands to run in the TrueNAS shell. The pull
|
||
refuses to run when the checkout still points at the old game's repository;
|
||
archive that checkout and clone the new repository first.
|
||
|
||
Preview checks without changing Git or TrueNAS:
|
||
|
||
```bash
|
||
pnpm publish:gitea -- --dry-run
|
||
```
|
||
|
||
Git push credentials still come from Git's credential manager. The configured
|
||
Gitea token handles release creation and APK uploads. Android signing keys remain
|
||
outside the repository.
|
||
|
||
## Controls
|
||
|
||
- `WASD` / left stick: move
|
||
- `Q` and `E` / D-pad: cycle party target
|
||
- `1`–`6`: cast Smite, Renew, Shield, Purify, Radiance, Flash Heal
|
||
- Gamepad: PlayStation `□`, `△`, `○`, `✕`, `L1`, `R1` map to those abilities
|
||
- `Select` / `Tab`: open or close the tactical interface on one-screen devices
|
||
- `M`: tactical map
|
||
- `I`: inventory and item tooltip
|
||
- `Enter` / `START`: begin or reset encounter
|
||
|
||
Touch controls on lower display support party targeting, ability casting, map, and inventory.
|
||
|
||
## Character model rollout and rollback
|
||
|
||
Healer characters use the modular `Rig_Medium` renderer by default. Version 1 composes
|
||
head, upper body, lower body, headwear, back item, main hand, and offhand slots while
|
||
continuing to use Aelia's shared animation set.
|
||
|
||
Load a hunter, then open **Appearance Lab** from the main menu. The upper display shows
|
||
the real in-game healer renderer with idle, walk, and cast previews. The lower display
|
||
selects healer class and cycles every available part. **Save look** persists the current
|
||
class, **Reset** restores its authored default, and **Cancel** discards drafts. **Compare
|
||
legacy** shows the previous whole-character model without deleting the modular selection.
|
||
|
||
Some source assets currently fuse related pieces, so version 1 exposes honest combined
|
||
slots such as face + hair, shirt + arms, and pants + shoes. These can split into finer
|
||
customization slots when compatible rigged assets are added.
|
||
|
||
The previous whole-GLB renderer remains intact during rollout. Use either rollback:
|
||
|
||
```text
|
||
?characterModels=legacy
|
||
VITE_CHARACTER_MODEL_MODE=legacy
|
||
```
|
||
|
||
The query changes one browser/app launch. The environment variable produces a legacy
|
||
build. Remove the switch to return to modular rendering.
|
||
|
||
## Current game scope
|
||
|
||
- Five-member AI party with Disc Priest healer
|
||
- Animated Druid healer, Knight tank, Ranger, Rogue, and Mage party models
|
||
- Animated bosses using canonical tracked game models
|
||
- Telegraph, charge, 0.75-second knockdown, and return-to-tank behavior
|
||
- Three-charge cycle into a five-second stack marker and 300-damage shared pounce
|
||
- Tank pressure, party-wide Cinder Nova, dispellable Ember Brand
|
||
- Full cooldown, mana, healing-over-time, shield absorption, and victory/defeat simulation
|
||
- True display ratios: 1920×1080 top and 1240×1080 bottom
|
||
- Android layout targets: approximately 960×540 CSS pixels top and 620×540 CSS pixels bottom
|
||
- Lower-screen typography scales against its own container, never the main page viewport
|
||
|
||
The Android build uses distinct display contexts that project one authoritative
|
||
game state across both physical Thor displays. PC and Steam Deck use the same top
|
||
surface with an adaptive tactical overlay.
|